WIP: corrections multiples formulaires et sérialisation
- Fix constructeurUtils: réordonner delete/add pour sauvegarder les fournisseurs - Fix prix/supplierPrice: envoyer en string pour DECIMAL Doctrine - Fix useMachineTypesApi: normaliser les requirements et forceRefresh - Fix SearchSelect: watch deep sur baseOptions - Debug logs temporaires pour pieceRequirements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,19 +62,30 @@ const deepClone = value => JSON.parse(JSON.stringify(value))
|
|||||||
|
|
||||||
const createFieldKey = () => `cf-${Math.random().toString(16).slice(2)}-${Date.now()}`
|
const createFieldKey = () => `cf-${Math.random().toString(16).slice(2)}-${Date.now()}`
|
||||||
|
|
||||||
|
const normalizeCustomField = (field = {}, index = 0) => {
|
||||||
|
const clone = deepClone(field)
|
||||||
|
if (clone.type === 'select') {
|
||||||
|
if (typeof clone.optionsText !== 'string' || !clone.optionsText.length) {
|
||||||
|
if (Array.isArray(clone.options)) {
|
||||||
|
clone.optionsText = clone.options.map(option => String(option).trim()).filter(Boolean).join('\n')
|
||||||
|
} else {
|
||||||
|
clone.optionsText = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const currentOrder =
|
||||||
|
typeof clone?.orderIndex === 'number' ? clone.orderIndex : index
|
||||||
|
clone.orderIndex = currentOrder
|
||||||
|
if (typeof clone?.__key !== 'string' || !clone.__key) {
|
||||||
|
clone.__key = createFieldKey()
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
const withNormalizedOrder = (items = []) => {
|
const withNormalizedOrder = (items = []) => {
|
||||||
if (!Array.isArray(items)) { return [] }
|
if (!Array.isArray(items)) { return [] }
|
||||||
return items
|
return items
|
||||||
.map((item, index) => {
|
.map((item, index) => normalizeCustomField(item, index))
|
||||||
const clone = deepClone(item)
|
|
||||||
const currentOrder =
|
|
||||||
typeof clone?.orderIndex === 'number' ? clone.orderIndex : index
|
|
||||||
clone.orderIndex = currentOrder
|
|
||||||
if (typeof clone?.__key !== 'string' || !clone.__key) {
|
|
||||||
clone.__key = createFieldKey()
|
|
||||||
}
|
|
||||||
return clone
|
|
||||||
})
|
|
||||||
.sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))
|
.sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))
|
||||||
.map((item, index) => ({ ...item, orderIndex: index }))
|
.map((item, index) => ({ ...item, orderIndex: index }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted } from 'vue'
|
import { computed, onMounted, watch } from 'vue'
|
||||||
import RequirementListEditor from '~/components/common/RequirementListEditor.vue'
|
import RequirementListEditor from '~/components/common/RequirementListEditor.vue'
|
||||||
import { usePieceTypes } from '~/composables/usePieceTypes'
|
import { usePieceTypes } from '~/composables/usePieceTypes'
|
||||||
|
|
||||||
@@ -91,5 +91,11 @@ onMounted(async () => {
|
|||||||
if (!pieceTypes.value.length) {
|
if (!pieceTypes.value.length) {
|
||||||
await loadPieceTypes()
|
await loadPieceTypes()
|
||||||
}
|
}
|
||||||
|
console.log('[PieceRequirementsSection] pieceTypes loaded:', pieceTypes.value.map(t => ({ id: t.id, name: t.name })))
|
||||||
|
console.log('[PieceRequirementsSection] requirements on mount:', props.modelValue.map(r => ({ id: r.id, typePieceId: r.typePieceId })))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
console.log('[PieceRequirementsSection] requirements updated:', newVal.map(r => ({ id: r.id, typePieceId: r.typePieceId })))
|
||||||
|
}, { deep: true })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -184,11 +184,13 @@ watch(
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
baseOptions,
|
baseOptions,
|
||||||
() => {
|
(newOptions) => {
|
||||||
if (!openDropdown.value) {
|
console.log('[SearchSelect] baseOptions changed, count:', newOptions.length, 'modelValue:', props.modelValue, 'selectedOption:', selectedOption.value?.id)
|
||||||
searchTerm.value = selectedOption.value ? resolveLabel(selectedOption.value) : searchTerm.value
|
if (!openDropdown.value && selectedOption.value) {
|
||||||
|
searchTerm.value = resolveLabel(selectedOption.value)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{ deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(openDropdown, (isOpen) => {
|
watch(openDropdown, (isOpen) => {
|
||||||
|
|||||||
@@ -10,18 +10,28 @@ const normalizeRequirementList = (value, relationKey) => {
|
|||||||
if (!Array.isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return value.map((entry) => {
|
return value.map((entry, index) => {
|
||||||
if (!entry || typeof entry !== 'object') {
|
if (!entry || typeof entry !== 'object') {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
const normalized = { ...entry }
|
const normalized = { ...entry }
|
||||||
|
const relationField = relationKey.replace('Id', '')
|
||||||
|
const relationValue = normalized[relationField]
|
||||||
|
console.log(`[normalizeRequirementList] Entry ${index}:`, {
|
||||||
|
relationKey,
|
||||||
|
relationField,
|
||||||
|
hasRelationKey: !!normalized[relationKey],
|
||||||
|
relationValue,
|
||||||
|
relationValueType: typeof relationValue
|
||||||
|
})
|
||||||
if (relationKey && !normalized[relationKey]) {
|
if (relationKey && !normalized[relationKey]) {
|
||||||
const relationValue = normalized[relationKey.replace('Id', '')]
|
|
||||||
const relationId = extractRelationId(relationValue)
|
const relationId = extractRelationId(relationValue)
|
||||||
|
console.log(`[normalizeRequirementList] Extracted ID:`, relationId)
|
||||||
if (relationId) {
|
if (relationId) {
|
||||||
normalized[relationKey] = relationId
|
normalized[relationKey] = relationId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(`[normalizeRequirementList] Normalized entry:`, normalized)
|
||||||
return normalized
|
return normalized
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -56,7 +66,7 @@ const extractCollection = (payload) => {
|
|||||||
|
|
||||||
export function useMachineTypesApi () {
|
export function useMachineTypesApi () {
|
||||||
const { showSuccess, showError, showInfo } = useToast()
|
const { showSuccess, showError, showInfo } = useToast()
|
||||||
const { get, post, patch, delete: del } = useApi()
|
const { get, post, put, delete: del } = useApi()
|
||||||
|
|
||||||
const loadMachineTypes = async () => {
|
const loadMachineTypes = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -94,7 +104,7 @@ export function useMachineTypesApi () {
|
|||||||
const updateMachineType = async (id, typeData) => {
|
const updateMachineType = async (id, typeData) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const result = await patch(`/type_machines/${id}`, typeData)
|
const result = await put(`/type_machines/${id}`, typeData)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const normalized = normalizeMachineType(result.data)
|
const normalized = normalizeMachineType(result.data)
|
||||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||||
@@ -130,19 +140,28 @@ export function useMachineTypesApi () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMachineTypeById = async (id) => {
|
const getMachineTypeById = async (id, forceRefresh = false) => {
|
||||||
// D'abord chercher dans le cache local
|
// D'abord chercher dans le cache local (sauf si forceRefresh)
|
||||||
const localType = machineTypes.value.find(type => type.id === id)
|
if (!forceRefresh) {
|
||||||
if (localType) {
|
const localType = machineTypes.value.find(type => type.id === id)
|
||||||
return { success: true, data: localType }
|
if (localType) {
|
||||||
|
return { success: true, data: localType }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si pas trouvé localement, récupérer depuis l'API
|
// Récupérer depuis l'API
|
||||||
try {
|
try {
|
||||||
const result = await get(`/type_machines/${id}`)
|
const result = await get(`/type_machines/${id}`)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Ajouter au cache local
|
const normalized = normalizeMachineType(result.data)
|
||||||
machineTypes.value.push(normalizeMachineType(result.data))
|
// Mettre à jour le cache local
|
||||||
|
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||||
|
if (index !== -1) {
|
||||||
|
machineTypes.value[index] = normalized
|
||||||
|
} else {
|
||||||
|
machineTypes.value.push(normalized)
|
||||||
|
}
|
||||||
|
return { success: true, data: normalized }
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -594,6 +594,15 @@ const selectedTypeStructure = computed<ComponentModelStructure | null>(() => {
|
|||||||
return structure ? normalizeStructureForEditor(structure) : null
|
return structure ? normalizeStructureForEditor(structure) : null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshCustomFieldInputs = (
|
||||||
|
structureOverride?: ComponentModelStructure | null,
|
||||||
|
valuesOverride?: any[] | null,
|
||||||
|
) => {
|
||||||
|
const structure = structureOverride ?? selectedTypeStructure.value ?? null
|
||||||
|
const values = valuesOverride ?? component.value?.customFieldValues ?? null
|
||||||
|
customFieldInputs.value = buildCustomFieldInputs(structure, values)
|
||||||
|
}
|
||||||
|
|
||||||
const requiredCustomFieldsFilled = computed(() =>
|
const requiredCustomFieldsFilled = computed(() =>
|
||||||
customFieldInputs.value.every((field) => {
|
customFieldInputs.value.every((field) => {
|
||||||
if (!field.required) {
|
if (!field.required) {
|
||||||
@@ -641,6 +650,7 @@ const fetchComponent = async () => {
|
|||||||
const customValues = await getCustomFieldValuesByEntity('composant', result.data.id)
|
const customValues = await getCustomFieldValuesByEntity('composant', result.data.id)
|
||||||
if (customValues.success && Array.isArray(customValues.data)) {
|
if (customValues.success && Array.isArray(customValues.data)) {
|
||||||
component.value.customFieldValues = customValues.data
|
component.value.customFieldValues = customValues.data
|
||||||
|
refreshCustomFieldInputs(undefined, customValues.data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
component.value = null
|
component.value = null
|
||||||
@@ -677,10 +687,7 @@ watch(
|
|||||||
void ensureConstructeurs(editionForm.constructeurIds)
|
void ensureConstructeurs(editionForm.constructeurIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
customFieldInputs.value = buildCustomFieldInputs(
|
refreshCustomFieldInputs(currentStructure, currentComponent.customFieldValues)
|
||||||
currentStructure,
|
|
||||||
currentComponent.customFieldValues,
|
|
||||||
)
|
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
},
|
},
|
||||||
@@ -691,10 +698,7 @@ watch(selectedTypeStructure, (currentStructure) => {
|
|||||||
if (!component.value) {
|
if (!component.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
customFieldInputs.value = buildCustomFieldInputs(
|
refreshCustomFieldInputs(currentStructure, component.value.customFieldValues)
|
||||||
currentStructure,
|
|
||||||
component.value.customFieldValues,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const submitEdition = async () => {
|
const submitEdition = async () => {
|
||||||
@@ -719,7 +723,7 @@ const submitEdition = async () => {
|
|||||||
if (rawPrice) {
|
if (rawPrice) {
|
||||||
const parsed = Number(rawPrice)
|
const parsed = Number(rawPrice)
|
||||||
if (!Number.isNaN(parsed)) {
|
if (!Number.isNaN(parsed)) {
|
||||||
payload.prix = parsed
|
payload.prix = String(parsed)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
payload.prix = null
|
payload.prix = null
|
||||||
|
|||||||
@@ -870,7 +870,7 @@ const submitCreation = async () => {
|
|||||||
if (rawPrice) {
|
if (rawPrice) {
|
||||||
const parsed = Number(rawPrice)
|
const parsed = Number(rawPrice)
|
||||||
if (!Number.isNaN(parsed)) {
|
if (!Number.isNaN(parsed)) {
|
||||||
payload.prix = parsed
|
payload.prix = String(parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useMachineTypesApi } from '~/composables/useMachineTypesApi'
|
import { useMachineTypesApi } from '~/composables/useMachineTypesApi'
|
||||||
import { useToast } from '~/composables/useToast'
|
import { useToast } from '~/composables/useToast'
|
||||||
|
import { extractRelationId } from '~/shared/apiRelations'
|
||||||
import IconLucidePlus from '~icons/lucide/plus'
|
import IconLucidePlus from '~icons/lucide/plus'
|
||||||
import IconLucideClipboardList from '~icons/lucide/clipboard-list'
|
import IconLucideClipboardList from '~icons/lucide/clipboard-list'
|
||||||
import IconLucideList from '~icons/lucide/list'
|
import IconLucideList from '~icons/lucide/list'
|
||||||
@@ -142,6 +143,20 @@ const parseOptions = (field = {}) => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toModelTypeIri = (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (typeof value === 'string' && value.startsWith('/api/model_types/')) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
const relationId = extractRelationId(value)
|
||||||
|
if (relationId) {
|
||||||
|
return `/api/model_types/${relationId}`
|
||||||
|
}
|
||||||
|
return typeof value === 'string' ? `/api/model_types/${value}` : undefined
|
||||||
|
}
|
||||||
|
|
||||||
const normalizeCustomFields = (fields = []) =>
|
const normalizeCustomFields = (fields = []) =>
|
||||||
fields
|
fields
|
||||||
.filter(field => field?.name && field.name.trim() !== '')
|
.filter(field => field?.name && field.name.trim() !== '')
|
||||||
@@ -165,9 +180,9 @@ const toIntegerOrNull = (value, fallback = null) => {
|
|||||||
|
|
||||||
const normalizeComponentRequirements = (requirements = []) =>
|
const normalizeComponentRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typeComposantId)
|
.filter(req => req?.typeComposantId || req?.typeComposant)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typeComposantId: req.typeComposantId,
|
typeComposant: toModelTypeIri(req.typeComposantId || req.typeComposant),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 1),
|
minCount: toIntegerOrNull(req.minCount, 1),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
@@ -180,9 +195,9 @@ const normalizeComponentRequirements = (requirements = []) =>
|
|||||||
|
|
||||||
const normalizePieceRequirements = (requirements = []) =>
|
const normalizePieceRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typePieceId)
|
.filter(req => req?.typePieceId || req?.typePiece)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typePieceId: req.typePieceId,
|
typePiece: toModelTypeIri(req.typePieceId || req.typePiece),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 0),
|
minCount: toIntegerOrNull(req.minCount, 0),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
@@ -195,9 +210,9 @@ const normalizePieceRequirements = (requirements = []) =>
|
|||||||
|
|
||||||
const normalizeProductRequirements = (requirements = []) =>
|
const normalizeProductRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typeProductId)
|
.filter(req => req?.typeProductId || req?.typeProduct)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typeProductId: req.typeProductId,
|
typeProduct: toModelTypeIri(req.typeProductId || req.typeProduct),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 0),
|
minCount: toIntegerOrNull(req.minCount, 0),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
|
|||||||
@@ -154,26 +154,26 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedType" class="space-y-3 rounded-lg border border-base-200 bg-base-200/40 p-4">
|
<div v-if="selectedType || resolvedStructure" class="space-y-3 rounded-lg border border-base-200 bg-base-200/40 p-4">
|
||||||
<div class="flex items-center justify-between gap-4">
|
<div class="flex items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="font-semibold text-base-content">Squelette sélectionné</h2>
|
<h2 class="font-semibold text-base-content">Squelette sélectionné</h2>
|
||||||
<p class="text-xs text-base-content/70">
|
<p class="text-xs text-base-content/70">
|
||||||
{{ selectedType.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }}
|
{{ selectedType?.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span class="badge badge-outline">{{ formatPieceStructurePreview(selectedType.structure) }}</span>
|
<span class="badge badge-outline">{{ formatPieceStructurePreview(resolvedStructure) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<details v-if="selectedType.structure" class="collapse collapse-arrow bg-base-100">
|
<details v-if="resolvedStructure" class="collapse collapse-arrow bg-base-100">
|
||||||
<summary class="collapse-title text-sm font-medium">
|
<summary class="collapse-title text-sm font-medium">
|
||||||
Consulter le détail du squelette
|
Consulter le détail du squelette
|
||||||
</summary>
|
</summary>
|
||||||
<div class="collapse-content space-y-2 text-sm text-base-content/80">
|
<div class="collapse-content space-y-2 text-sm text-base-content/80">
|
||||||
<div v-if="getStructureCustomFields(selectedType.structure).length" class="space-y-1">
|
<div v-if="getStructureCustomFields(resolvedStructure).length" class="space-y-1">
|
||||||
<h3 class="font-semibold text-sm text-base-content">Champs personnalisés</h3>
|
<h3 class="font-semibold text-sm text-base-content">Champs personnalisés</h3>
|
||||||
<ul class="list-disc list-inside space-y-1">
|
<ul class="list-disc list-inside space-y-1">
|
||||||
<li v-for="field in getStructureCustomFields(selectedType.structure)" :key="field.name">
|
<li v-for="field in getStructureCustomFields(resolvedStructure)" :key="field.name">
|
||||||
<span class="font-medium">{{ field.name }}</span>
|
<span class="font-medium">{{ field.name }}</span>
|
||||||
<span v-if="field.value !== undefined && field.value !== null"> : {{ field.value }}</span>
|
<span v-if="field.value !== undefined && field.value !== null"> : {{ field.value }}</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -395,12 +395,14 @@ import { useApi } from '~/composables/useApi'
|
|||||||
import { useToast } from '~/composables/useToast'
|
import { useToast } from '~/composables/useToast'
|
||||||
import { useDocuments } from '~/composables/useDocuments'
|
import { useDocuments } from '~/composables/useDocuments'
|
||||||
import { useConstructeurs } from '~/composables/useConstructeurs'
|
import { useConstructeurs } from '~/composables/useConstructeurs'
|
||||||
|
import { extractRelationId } from '~/shared/apiRelations'
|
||||||
import { getFileIcon } from '~/utils/fileIcons'
|
import { getFileIcon } from '~/utils/fileIcons'
|
||||||
import { canPreviewDocument, isImageDocument, isPdfDocument } from '~/utils/documentPreview'
|
import { canPreviewDocument, isImageDocument, isPdfDocument } from '~/utils/documentPreview'
|
||||||
import { formatPieceStructurePreview } from '~/shared/modelUtils'
|
import { formatPieceStructurePreview } from '~/shared/modelUtils'
|
||||||
import { uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
import { uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
||||||
import type { PieceModelProduct, PieceModelStructure } from '~/shared/types/inventory'
|
import type { PieceModelProduct, PieceModelStructure } from '~/shared/types/inventory'
|
||||||
import type { ModelType } from '~/services/modelTypes'
|
import type { ModelType } from '~/services/modelTypes'
|
||||||
|
import { getModelType } from '~/services/modelTypes'
|
||||||
|
|
||||||
interface PieceCatalogType extends ModelType {
|
interface PieceCatalogType extends ModelType {
|
||||||
structure: PieceModelStructure | null
|
structure: PieceModelStructure | null
|
||||||
@@ -424,7 +426,7 @@ const router = useRouter()
|
|||||||
const { get } = useApi()
|
const { get } = useApi()
|
||||||
const { pieceTypes, loadPieceTypes } = usePieceTypes()
|
const { pieceTypes, loadPieceTypes } = usePieceTypes()
|
||||||
const { updatePiece } = usePieces()
|
const { updatePiece } = usePieces()
|
||||||
const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields()
|
const { upsertCustomFieldValue, updateCustomFieldValue, getCustomFieldValuesByEntity } = useCustomFields()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const { loadDocumentsByPiece, uploadDocuments, deleteDocument } = useDocuments()
|
const { loadDocumentsByPiece, uploadDocuments, deleteDocument } = useDocuments()
|
||||||
const { ensureConstructeurs } = useConstructeurs()
|
const { ensureConstructeurs } = useConstructeurs()
|
||||||
@@ -440,6 +442,7 @@ const previewDocument = ref<any | null>(null)
|
|||||||
const previewVisible = ref(false)
|
const previewVisible = ref(false)
|
||||||
|
|
||||||
const selectedTypeId = ref<string>('')
|
const selectedTypeId = ref<string>('')
|
||||||
|
const pieceTypeDetails = ref<any | null>(null)
|
||||||
const editionForm = reactive({
|
const editionForm = reactive({
|
||||||
name: '' as string,
|
name: '' as string,
|
||||||
reference: '' as string,
|
reference: '' as string,
|
||||||
@@ -451,6 +454,18 @@ const editionForm = reactive({
|
|||||||
const customFieldInputs = ref<CustomFieldInput[]>([])
|
const customFieldInputs = ref<CustomFieldInput[]>([])
|
||||||
const documentIcon = (doc: any) =>
|
const documentIcon = (doc: any) =>
|
||||||
getFileIcon({ name: doc?.filename || doc?.name, mime: doc?.mimeType })
|
getFileIcon({ name: doc?.filename || doc?.name, mime: doc?.mimeType })
|
||||||
|
const resolvedStructure = computed<PieceModelStructure | null>(() =>
|
||||||
|
pieceTypeDetails.value?.structure ?? selectedType.value?.structure ?? null,
|
||||||
|
)
|
||||||
|
|
||||||
|
const refreshCustomFieldInputs = (
|
||||||
|
structureOverride?: PieceModelStructure | null,
|
||||||
|
valuesOverride?: any[] | null,
|
||||||
|
) => {
|
||||||
|
const structure = structureOverride ?? resolvedStructure.value ?? null
|
||||||
|
const values = valuesOverride ?? piece.value?.customFieldValues ?? null
|
||||||
|
customFieldInputs.value = buildCustomFieldInputs(structure, values)
|
||||||
|
}
|
||||||
const formatSize = (size: number | null | undefined) => {
|
const formatSize = (size: number | null | undefined) => {
|
||||||
if (size === null || size === undefined) {
|
if (size === null || size === undefined) {
|
||||||
return '—'
|
return '—'
|
||||||
@@ -578,7 +593,7 @@ const selectedType = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const structureProducts = computed(() =>
|
const structureProducts = computed(() =>
|
||||||
getStructureProducts(selectedType.value?.structure ?? null),
|
getStructureProducts(resolvedStructure.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
const requiresProductSelection = computed(() => structureProducts.value.length > 0)
|
const requiresProductSelection = computed(() => structureProducts.value.length > 0)
|
||||||
@@ -659,12 +674,37 @@ const fetchPiece = async () => {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
piece.value = result.data
|
piece.value = result.data
|
||||||
pieceDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : []
|
pieceDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : []
|
||||||
|
const customValues = await getCustomFieldValuesByEntity('piece', result.data.id)
|
||||||
|
if (customValues.success && Array.isArray(customValues.data)) {
|
||||||
|
piece.value.customFieldValues = customValues.data
|
||||||
|
refreshCustomFieldInputs(undefined, customValues.data)
|
||||||
|
}
|
||||||
|
await loadPieceTypeDetails(result.data)
|
||||||
} else {
|
} else {
|
||||||
piece.value = null
|
piece.value = null
|
||||||
pieceDocuments.value = []
|
pieceDocuments.value = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadPieceTypeDetails = async (currentPiece: any) => {
|
||||||
|
const typeId = currentPiece?.typePieceId
|
||||||
|
|| extractRelationId(currentPiece?.typePiece)
|
||||||
|
|| ''
|
||||||
|
if (!typeId) {
|
||||||
|
pieceTypeDetails.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const type = await getModelType(typeId)
|
||||||
|
if (type && typeof type === 'object') {
|
||||||
|
pieceTypeDetails.value = type
|
||||||
|
refreshCustomFieldInputs(type.structure ?? null, currentPiece?.customFieldValues ?? null)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
pieceTypeDetails.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let initialized = false
|
let initialized = false
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -674,7 +714,13 @@ watch(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedTypeId.value = currentPiece.typePieceId || ''
|
const resolvedTypeId = currentPiece.typePieceId
|
||||||
|
|| extractRelationId(currentPiece.typePiece)
|
||||||
|
|| ''
|
||||||
|
if (resolvedTypeId && !currentPiece.typePieceId) {
|
||||||
|
currentPiece.typePieceId = resolvedTypeId
|
||||||
|
}
|
||||||
|
selectedTypeId.value = resolvedTypeId
|
||||||
|
|
||||||
editionForm.name = currentPiece.name || ''
|
editionForm.name = currentPiece.name || ''
|
||||||
editionForm.reference = currentPiece.reference || ''
|
editionForm.reference = currentPiece.reference || ''
|
||||||
@@ -689,10 +735,7 @@ watch(
|
|||||||
void ensureConstructeurs(editionForm.constructeurIds)
|
void ensureConstructeurs(editionForm.constructeurIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
customFieldInputs.value = buildCustomFieldInputs(
|
refreshCustomFieldInputs(currentType?.structure ?? null, currentPiece.customFieldValues)
|
||||||
currentType?.structure ?? null,
|
|
||||||
currentPiece.customFieldValues,
|
|
||||||
)
|
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
},
|
},
|
||||||
@@ -703,10 +746,16 @@ watch(selectedType, (currentType) => {
|
|||||||
if (!piece.value || !currentType) {
|
if (!piece.value || !currentType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
customFieldInputs.value = buildCustomFieldInputs(
|
if (!pieceTypeDetails.value) {
|
||||||
currentType.structure,
|
refreshCustomFieldInputs(currentType.structure, piece.value.customFieldValues)
|
||||||
piece.value.customFieldValues,
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
|
watch(resolvedStructure, (currentStructure) => {
|
||||||
|
if (!piece.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
refreshCustomFieldInputs(currentStructure, piece.value.customFieldValues)
|
||||||
})
|
})
|
||||||
|
|
||||||
const submitEdition = async () => {
|
const submitEdition = async () => {
|
||||||
@@ -744,7 +793,7 @@ const submitEdition = async () => {
|
|||||||
if (rawPrice) {
|
if (rawPrice) {
|
||||||
const parsed = Number(rawPrice)
|
const parsed = Number(rawPrice)
|
||||||
if (!Number.isNaN(parsed)) {
|
if (!Number.isNaN(parsed)) {
|
||||||
payload.prix = parsed
|
payload.prix = String(parsed)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
payload.prix = null
|
payload.prix = null
|
||||||
|
|||||||
@@ -504,7 +504,7 @@ const submitCreation = async () => {
|
|||||||
if (rawPrice) {
|
if (rawPrice) {
|
||||||
const parsed = Number(rawPrice)
|
const parsed = Number(rawPrice)
|
||||||
if (!Number.isNaN(parsed)) {
|
if (!Number.isNaN(parsed)) {
|
||||||
payload.prix = parsed
|
payload.prix = String(parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ const route = useRoute()
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const { getProduct, updateProduct } = useProducts()
|
const { getProduct, updateProduct } = useProducts()
|
||||||
const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields()
|
const { upsertCustomFieldValue, updateCustomFieldValue, getCustomFieldValuesByEntity } = useCustomFields()
|
||||||
const {
|
const {
|
||||||
loadDocumentsByProduct,
|
loadDocumentsByProduct,
|
||||||
uploadDocuments: uploadProductDocuments,
|
uploadDocuments: uploadProductDocuments,
|
||||||
@@ -373,6 +373,15 @@ const productDocuments = ref<any[]>([])
|
|||||||
const previewDocument = ref<any | null>(null)
|
const previewDocument = ref<any | null>(null)
|
||||||
const previewVisible = ref(false)
|
const previewVisible = ref(false)
|
||||||
|
|
||||||
|
const refreshCustomFieldInputs = (
|
||||||
|
structureOverride?: ProductModelStructure | null,
|
||||||
|
valuesOverride?: any[] | null,
|
||||||
|
) => {
|
||||||
|
const nextStructure = structureOverride ?? structure.value ?? null
|
||||||
|
const nextValues = valuesOverride ?? product.value?.customFieldValues ?? null
|
||||||
|
customFieldInputs.value = buildCustomFieldInputs(nextStructure, nextValues)
|
||||||
|
}
|
||||||
|
|
||||||
const editionForm = reactive({
|
const editionForm = reactive({
|
||||||
name: '' as string,
|
name: '' as string,
|
||||||
reference: '' as string,
|
reference: '' as string,
|
||||||
@@ -493,6 +502,11 @@ const loadProduct = async () => {
|
|||||||
product.value = result.data
|
product.value = result.data
|
||||||
productDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : []
|
productDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : []
|
||||||
await loadProductType()
|
await loadProductType()
|
||||||
|
const customValues = await getCustomFieldValuesByEntity('product', result.data.id)
|
||||||
|
if (customValues.success && Array.isArray(customValues.data)) {
|
||||||
|
product.value.customFieldValues = customValues.data
|
||||||
|
refreshCustomFieldInputs(undefined, customValues.data)
|
||||||
|
}
|
||||||
await hydrateForm()
|
await hydrateForm()
|
||||||
await refreshDocuments()
|
await refreshDocuments()
|
||||||
} else {
|
} else {
|
||||||
@@ -582,7 +596,7 @@ const hydrateForm = async () => {
|
|||||||
editionForm.supplierPrice = product.value.supplierPrice !== null && product.value.supplierPrice !== undefined
|
editionForm.supplierPrice = product.value.supplierPrice !== null && product.value.supplierPrice !== undefined
|
||||||
? String(product.value.supplierPrice)
|
? String(product.value.supplierPrice)
|
||||||
: ''
|
: ''
|
||||||
customFieldInputs.value = buildCustomFieldInputs(structure.value, product.value.customFieldValues)
|
refreshCustomFieldInputs(structure.value, product.value.customFieldValues)
|
||||||
if (editionForm.constructeurIds.length) {
|
if (editionForm.constructeurIds.length) {
|
||||||
await ensureConstructeurs(editionForm.constructeurIds)
|
await ensureConstructeurs(editionForm.constructeurIds)
|
||||||
}
|
}
|
||||||
@@ -691,11 +705,13 @@ const submitEdition = async () => {
|
|||||||
constructeurIds,
|
constructeurIds,
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawPrice = editionForm.supplierPrice.trim()
|
const rawPrice = typeof editionForm.supplierPrice === 'string'
|
||||||
payload.supplierPrice = rawPrice
|
? editionForm.supplierPrice.trim()
|
||||||
|
: editionForm.supplierPrice
|
||||||
|
payload.supplierPrice = rawPrice !== '' && rawPrice !== null && rawPrice !== undefined
|
||||||
? Number.isNaN(Number(rawPrice))
|
? Number.isNaN(Number(rawPrice))
|
||||||
? null
|
? null
|
||||||
: Number(rawPrice)
|
: String(Number(rawPrice))
|
||||||
: null
|
: null
|
||||||
|
|
||||||
saving.value = true
|
saving.value = true
|
||||||
@@ -730,20 +746,29 @@ const saveCustomFieldValues = async (productId: string) => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!field.customFieldId) {
|
const metadata = field.customFieldId
|
||||||
continue
|
? undefined
|
||||||
}
|
: { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required }
|
||||||
|
|
||||||
const result = await upsertCustomFieldValue(
|
const result = await upsertCustomFieldValue(
|
||||||
field.customFieldId,
|
field.customFieldId,
|
||||||
'product',
|
'product',
|
||||||
productId,
|
productId,
|
||||||
String(value ?? ''),
|
String(value ?? ''),
|
||||||
{ customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required },
|
metadata,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
failed.push(field.name)
|
failed.push(field.name)
|
||||||
|
} else {
|
||||||
|
const createdValue = result.data
|
||||||
|
if (createdValue?.id) {
|
||||||
|
field.customFieldValueId = createdValue.id
|
||||||
|
}
|
||||||
|
const resolvedId = createdValue?.customField?.id || field.customFieldId
|
||||||
|
if (resolvedId) {
|
||||||
|
field.customFieldId = resolvedId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return failed
|
return failed
|
||||||
|
|||||||
@@ -425,11 +425,13 @@ const buildPayload = () => {
|
|||||||
|
|
||||||
payload.constructeurIds = uniqueConstructeurIds(creationForm.constructeurIds)
|
payload.constructeurIds = uniqueConstructeurIds(creationForm.constructeurIds)
|
||||||
|
|
||||||
const rawPrice = creationForm.supplierPrice.trim()
|
const rawPrice = typeof creationForm.supplierPrice === 'string'
|
||||||
if (rawPrice) {
|
? creationForm.supplierPrice.trim()
|
||||||
|
: creationForm.supplierPrice
|
||||||
|
if (rawPrice !== '' && rawPrice !== null && rawPrice !== undefined) {
|
||||||
const parsed = Number(rawPrice)
|
const parsed = Number(rawPrice)
|
||||||
if (!Number.isNaN(parsed)) {
|
if (!Number.isNaN(parsed)) {
|
||||||
payload.supplierPrice = parsed
|
payload.supplierPrice = String(parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,19 +488,31 @@ const submitCreation = async () => {
|
|||||||
const saveCustomFieldValues = async (productId: string) => {
|
const saveCustomFieldValues = async (productId: string) => {
|
||||||
const failed: string[] = []
|
const failed: string[] = []
|
||||||
for (const field of customFieldInputs.value) {
|
for (const field of customFieldInputs.value) {
|
||||||
if (!field.customFieldId || !field.name) {
|
if (!field.name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const value = field.value ?? ''
|
const value = field.value ?? ''
|
||||||
|
const metadata = field.customFieldId
|
||||||
|
? undefined
|
||||||
|
: { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required }
|
||||||
const result = await upsertCustomFieldValue(
|
const result = await upsertCustomFieldValue(
|
||||||
field.customFieldId,
|
field.customFieldId,
|
||||||
'product',
|
'product',
|
||||||
productId,
|
productId,
|
||||||
String(value ?? ''),
|
String(value ?? ''),
|
||||||
{ customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required },
|
metadata,
|
||||||
)
|
)
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
failed.push(field.name)
|
failed.push(field.name)
|
||||||
|
} else {
|
||||||
|
const createdValue = result.data
|
||||||
|
if (createdValue?.id) {
|
||||||
|
field.customFieldValueId = createdValue.id
|
||||||
|
}
|
||||||
|
const resolvedId = createdValue?.customField?.id || field.customFieldId
|
||||||
|
if (resolvedId) {
|
||||||
|
field.customFieldId = resolvedId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return failed
|
return failed
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import { ref, onMounted } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useMachineTypesApi } from '~/composables/useMachineTypesApi'
|
import { useMachineTypesApi } from '~/composables/useMachineTypesApi'
|
||||||
import { useToast } from '~/composables/useToast'
|
import { useToast } from '~/composables/useToast'
|
||||||
|
import { extractRelationId } from '~/shared/apiRelations'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -90,6 +91,20 @@ const parseOptions = (field = {}) => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toModelTypeIri = (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (typeof value === 'string' && value.startsWith('/api/model_types/')) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
const relationId = extractRelationId(value)
|
||||||
|
if (relationId) {
|
||||||
|
return `/api/model_types/${relationId}`
|
||||||
|
}
|
||||||
|
return typeof value === 'string' ? `/api/model_types/${value}` : undefined
|
||||||
|
}
|
||||||
|
|
||||||
const normalizeCustomFields = (fields = []) =>
|
const normalizeCustomFields = (fields = []) =>
|
||||||
fields
|
fields
|
||||||
.filter(field => field?.name && field.name.trim() !== '')
|
.filter(field => field?.name && field.name.trim() !== '')
|
||||||
@@ -113,9 +128,9 @@ const toIntegerOrNull = (value, fallback = null) => {
|
|||||||
|
|
||||||
const normalizeComponentRequirements = (requirements = []) =>
|
const normalizeComponentRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typeComposantId)
|
.filter(req => req?.typeComposantId || req?.typeComposant)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typeComposantId: req.typeComposantId,
|
typeComposant: toModelTypeIri(req.typeComposantId || req.typeComposant),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 1),
|
minCount: toIntegerOrNull(req.minCount, 1),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
@@ -128,9 +143,9 @@ const normalizeComponentRequirements = (requirements = []) =>
|
|||||||
|
|
||||||
const normalizePieceRequirements = (requirements = []) =>
|
const normalizePieceRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typePieceId)
|
.filter(req => req?.typePieceId || req?.typePiece)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typePieceId: req.typePieceId,
|
typePiece: toModelTypeIri(req.typePieceId || req.typePiece),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 0),
|
minCount: toIntegerOrNull(req.minCount, 0),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
@@ -143,9 +158,9 @@ const normalizePieceRequirements = (requirements = []) =>
|
|||||||
|
|
||||||
const normalizeProductRequirements = (requirements = []) =>
|
const normalizeProductRequirements = (requirements = []) =>
|
||||||
requirements
|
requirements
|
||||||
.filter(req => req?.typeProductId)
|
.filter(req => req?.typeProductId || req?.typeProduct)
|
||||||
.map((req, index) => ({
|
.map((req, index) => ({
|
||||||
typeProductId: req.typeProductId,
|
typeProduct: toModelTypeIri(req.typeProductId || req.typeProduct),
|
||||||
label: req.label?.trim() ? req.label.trim() : undefined,
|
label: req.label?.trim() ? req.label.trim() : undefined,
|
||||||
minCount: toIntegerOrNull(req.minCount, 0),
|
minCount: toIntegerOrNull(req.minCount, 0),
|
||||||
maxCount: toIntegerOrNull(req.maxCount, null),
|
maxCount: toIntegerOrNull(req.maxCount, null),
|
||||||
@@ -194,7 +209,7 @@ onMounted(async () => {
|
|||||||
console.log('=== EDIT TYPE PAGE LOADING ===')
|
console.log('=== EDIT TYPE PAGE LOADING ===')
|
||||||
console.log('Loading type with ID:', typeId)
|
console.log('Loading type with ID:', typeId)
|
||||||
|
|
||||||
const result = await getMachineTypeById(typeId)
|
const result = await getMachineTypeById(typeId, true)
|
||||||
console.log('API Result:', result)
|
console.log('API Result:', result)
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|||||||
@@ -117,21 +117,48 @@ export const formatConstructeurContact = (
|
|||||||
export const buildConstructeurRequestPayload = <T extends Record<string, any>>(
|
export const buildConstructeurRequestPayload = <T extends Record<string, any>>(
|
||||||
payload: T,
|
payload: T,
|
||||||
): T & { constructeurs?: string[] } => {
|
): T & { constructeurs?: string[] } => {
|
||||||
const ids = uniqueConstructeurIds(
|
const collected = new Set(uniqueConstructeurIds(
|
||||||
payload?.constructeurIds,
|
payload?.constructeurIds,
|
||||||
payload?.constructeurId,
|
payload?.constructeurId,
|
||||||
payload?.constructeur,
|
payload?.constructeur,
|
||||||
payload?.constructeurs,
|
payload?.constructeurs,
|
||||||
);
|
));
|
||||||
|
|
||||||
|
if (!collected.size) {
|
||||||
|
const fallbackLists = [
|
||||||
|
payload?.constructeurIds,
|
||||||
|
payload?.constructeurs,
|
||||||
|
];
|
||||||
|
fallbackLists.forEach((list) => {
|
||||||
|
if (!Array.isArray(list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
const id = toStringId(item);
|
||||||
|
if (id) {
|
||||||
|
collected.add(id);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isObject(item) && typeof item.id === 'string') {
|
||||||
|
collected.add(item.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = Array.from(collected);
|
||||||
|
|
||||||
const next = { ...payload } as Record<string, any>;
|
const next = { ...payload } as Record<string, any>;
|
||||||
if (ids.length) {
|
|
||||||
next.constructeurs = ids.map((id) => `/api/constructeurs/${id}`);
|
|
||||||
}
|
|
||||||
delete next.constructeurId;
|
delete next.constructeurId;
|
||||||
delete next.constructeur;
|
delete next.constructeur;
|
||||||
delete next.constructeurs;
|
delete next.constructeurs;
|
||||||
delete next.constructeurIds;
|
delete next.constructeurIds;
|
||||||
|
|
||||||
|
if (ids.length) {
|
||||||
|
next.constructeurs = ids.map((id) => `/api/constructeurs/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
return next as T & { constructeurs?: string[] };
|
return next as T & { constructeurs?: string[] };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export default defineNuxtConfig({
|
|||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
devServer: {
|
devServer: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 3001
|
port: 3000
|
||||||
},
|
},
|
||||||
modules: [
|
modules: [
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user