Compare commits
6 Commits
v1.9.0
...
50d8dde6d5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50d8dde6d5 | ||
|
|
9b40f9f2c7 | ||
|
|
721963449b | ||
|
|
22ba9a8d05 | ||
|
|
695d56a6d3 | ||
|
|
5c31045e83 |
@@ -24,6 +24,12 @@
|
|||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<h3 class="text-lg font-semibold">
|
<h3 class="text-lg font-semibold">
|
||||||
{{ pieceData.name }}
|
{{ pieceData.name }}
|
||||||
|
<span
|
||||||
|
v-if="displayQuantity > 1"
|
||||||
|
class="text-sm font-normal text-base-content/60 ml-1"
|
||||||
|
>
|
||||||
|
×{{ displayQuantity }}
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-wrap gap-2 mt-2">
|
<div class="flex flex-wrap gap-2 mt-2">
|
||||||
<span v-if="piece.parentComponentName" class="badge badge-ghost badge-sm">
|
<span v-if="piece.parentComponentName" class="badge badge-ghost badge-sm">
|
||||||
@@ -63,6 +69,19 @@
|
|||||||
<div v-show="!isCollapsed" class="space-y-4">
|
<div v-show="!isCollapsed" class="space-y-4">
|
||||||
<div class="p-4 bg-base-100 border border-base-200 rounded-lg">
|
<div class="p-4 bg-base-100 border border-base-200 rounded-lg">
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
|
<div v-if="!piece.parentComponentLinkId && isEditMode" class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text text-sm">Quantité</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model.number="pieceData.quantity"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
step="1"
|
||||||
|
class="input input-bordered input-sm md:input-md w-24"
|
||||||
|
@blur="updatePiece"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="font-medium">Référence:</span>
|
<span class="font-medium">Référence:</span>
|
||||||
<input
|
<input
|
||||||
@@ -272,6 +291,11 @@ const pieceData = reactive({
|
|||||||
reference: props.piece.reference || '',
|
reference: props.piece.reference || '',
|
||||||
prix: props.piece.prix || '',
|
prix: props.piece.prix || '',
|
||||||
productId: props.piece.product?.id || props.piece.productId || null,
|
productId: props.piece.product?.id || props.piece.productId || null,
|
||||||
|
quantity: props.piece.quantity ?? 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
const displayQuantity = computed(() => {
|
||||||
|
return pieceData.quantity ?? 1
|
||||||
})
|
})
|
||||||
|
|
||||||
// --- Products ---
|
// --- Products ---
|
||||||
@@ -439,6 +463,7 @@ const updatePiece = () => {
|
|||||||
...props.piece,
|
...props.piece,
|
||||||
...pieceData,
|
...pieceData,
|
||||||
prix: parsedPrice,
|
prix: parsedPrice,
|
||||||
|
quantity: pieceData.quantity ?? 1,
|
||||||
productId: pieceData.productId || null,
|
productId: pieceData.productId || null,
|
||||||
product,
|
product,
|
||||||
constructeurIds: pieceConstructeurIds.value,
|
constructeurIds: pieceConstructeurIds.value,
|
||||||
@@ -478,11 +503,12 @@ watch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [props.piece.name, props.piece.reference, props.piece.prix],
|
() => [props.piece.name, props.piece.reference, props.piece.prix, props.piece.quantity],
|
||||||
() => {
|
() => {
|
||||||
pieceData.name = props.piece.name || ''
|
pieceData.name = props.piece.name || ''
|
||||||
pieceData.reference = props.piece.reference || ''
|
pieceData.reference = props.piece.reference || ''
|
||||||
pieceData.prix = props.piece.prix || ''
|
pieceData.prix = props.piece.prix || ''
|
||||||
|
pieceData.quantity = props.piece.quantity ?? 1
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -490,6 +516,7 @@ onMounted(() => {
|
|||||||
pieceData.name = props.piece.name || ''
|
pieceData.name = props.piece.name || ''
|
||||||
pieceData.reference = props.piece.reference || ''
|
pieceData.reference = props.piece.reference || ''
|
||||||
pieceData.prix = props.piece.prix || ''
|
pieceData.prix = props.piece.prix || ''
|
||||||
|
pieceData.quantity = props.piece.quantity ?? 1
|
||||||
loadProducts().catch(() => {})
|
loadProducts().catch(() => {})
|
||||||
if (pieceData.productId) ensureProductLoaded(pieceData.productId)
|
if (pieceData.productId) ensureProductLoaded(pieceData.productId)
|
||||||
if (!props.piece.documents?.length) refreshDocuments()
|
if (!props.piece.documents?.length) refreshDocuments()
|
||||||
|
|||||||
@@ -280,6 +280,18 @@
|
|||||||
{{ piece.typePieceId ? `Sélection : ${getPieceTypeLabel(piece.typePieceId) || 'Inconnue'}` : 'Aucune famille sélectionnée' }}
|
{{ piece.typePieceId ? `Sélection : ${getPieceTypeLabel(piece.typePieceId) || 'Inconnue'}` : 'Aucune famille sélectionnée' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label py-1"><span class="label-text text-xs">Quantité</span></label>
|
||||||
|
<input
|
||||||
|
v-model.number="piece.quantity"
|
||||||
|
type="number"
|
||||||
|
:min="1"
|
||||||
|
step="1"
|
||||||
|
placeholder="Qté"
|
||||||
|
class="input input-bordered input-sm md:input-md w-20"
|
||||||
|
@input="piece.quantity = Math.max(1, piece.quantity || 1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button v-if="!isPieceLocked(index)" type="button" class="btn btn-error btn-xs btn-square" @click="removePiece(index)">
|
<button v-if="!isPieceLocked(index)" type="button" class="btn btn-error btn-xs btn-square" @click="removePiece(index)">
|
||||||
<IconLucideTrash class="w-4 h-4" aria-hidden="true" />
|
<IconLucideTrash class="w-4 h-4" aria-hidden="true" />
|
||||||
|
|||||||
@@ -72,23 +72,23 @@
|
|||||||
placeholder="Rechercher un ou plusieurs fournisseurs..."
|
placeholder="Rechercher un ou plusieurs fournisseurs..."
|
||||||
@update:modelValue="$emit('update:constructeur-ids', $event)"
|
@update:modelValue="$emit('update:constructeur-ids', $event)"
|
||||||
/>
|
/>
|
||||||
<div v-else class="input input-bordered bg-base-200">
|
<div v-else class="border border-base-300 rounded-btn bg-base-200 px-4 py-2 min-h-12 flex items-center">
|
||||||
<div v-if="machineConstructeursDisplay.length" class="space-y-1">
|
<div v-if="machineConstructeursDisplay.length" class="flex flex-wrap gap-2">
|
||||||
<div
|
<span
|
||||||
v-for="constructeur in machineConstructeursDisplay"
|
v-for="constructeur in machineConstructeursDisplay"
|
||||||
:key="constructeur.id"
|
:key="constructeur.id"
|
||||||
class="flex flex-col"
|
class="badge badge-ghost gap-1"
|
||||||
>
|
>
|
||||||
<span class="font-medium">{{ constructeur.name }}</span>
|
{{ constructeur.name }}
|
||||||
<span
|
<span
|
||||||
v-if="formatConstructeurContactSummary(constructeur)"
|
v-if="formatConstructeurContactSummary(constructeur)"
|
||||||
class="text-xs text-base-content/50"
|
class="text-xs opacity-60"
|
||||||
>
|
>
|
||||||
{{ formatConstructeurContactSummary(constructeur) }}
|
· {{ formatConstructeurContactSummary(constructeur) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span v-else class="font-medium">Non défini</span>
|
<span v-else class="text-base-content/50">Non défini</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -299,6 +299,10 @@ export function useComponentEdit(componentId: string) {
|
|||||||
payload.prix = null
|
payload.prix = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.value.structure) {
|
||||||
|
payload.structure = component.value.structure
|
||||||
|
}
|
||||||
|
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
const result = await updateComposant(component.value.id, payload)
|
const result = await updateComposant(component.value.id, payload)
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export function useStructureNodeCrud(props: StructureNodeCrudDeps) {
|
|||||||
reference: '',
|
reference: '',
|
||||||
familyCode: '',
|
familyCode: '',
|
||||||
role: '',
|
role: '',
|
||||||
|
quantity: 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,9 +166,20 @@
|
|||||||
<div v-if="structureSelections.pieces.length" class="space-y-2">
|
<div v-if="structureSelections.pieces.length" class="space-y-2">
|
||||||
<h3 class="font-semibold text-sm text-base-content">Pièces choisies</h3>
|
<h3 class="font-semibold text-sm text-base-content">Pièces choisies</h3>
|
||||||
<ul class="list-disc list-inside space-y-1 text-sm">
|
<ul class="list-disc list-inside space-y-1 text-sm">
|
||||||
<li v-for="entry in structureSelections.pieces" :key="`selected-piece-${entry.path}-${entry.id}`">
|
<li v-for="entry in structureSelections.pieces" :key="`selected-piece-${entry.path}-${entry.id}`" class="flex items-center gap-2">
|
||||||
<span class="font-medium">{{ entry.resolvedName }}</span>
|
<span class="font-medium">{{ entry.resolvedName }}</span>
|
||||||
|
<span v-if="(entry.quantity ?? 1) > 1" class="text-sm text-base-content/60">×{{ entry.quantity }}</span>
|
||||||
<span class="text-xs text-base-content/70"> — {{ entry.requirementLabel }}</span>
|
<span class="text-xs text-base-content/70"> — {{ entry.requirementLabel }}</span>
|
||||||
|
<input
|
||||||
|
v-if="canEdit && entry._definition"
|
||||||
|
v-model.number="entry._definition.quantity"
|
||||||
|
type="number"
|
||||||
|
:min="1"
|
||||||
|
step="1"
|
||||||
|
placeholder="Qté"
|
||||||
|
class="input input-bordered input-xs w-16 ml-auto"
|
||||||
|
@input="entry._definition.quantity = Math.max(1, entry._definition.quantity || 1)"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -175,6 +175,9 @@ export const normalizeStructureForSave = (input: any): any => {
|
|||||||
if (piece.reference) {
|
if (piece.reference) {
|
||||||
payload.reference = piece.reference
|
payload.reference = piece.reference
|
||||||
}
|
}
|
||||||
|
if ((piece as any).quantity !== undefined && (piece as any).quantity >= 1) {
|
||||||
|
payload.quantity = (piece as any).quantity
|
||||||
|
}
|
||||||
return payload
|
return payload
|
||||||
}) as any
|
}) as any
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ export const hydratePieces = (pieces: any[]): ComponentModelPiece[] => {
|
|||||||
reference: piece?.reference ?? '',
|
reference: piece?.reference ?? '',
|
||||||
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
||||||
role: piece?.role ?? '',
|
role: piece?.role ?? '',
|
||||||
|
...(piece?.quantity !== undefined && piece.quantity >= 1 ? { quantity: piece.quantity } : {}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +176,7 @@ export const mapComponentPieces = (pieces: any[]): ComponentModelPiece[] => {
|
|||||||
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
||||||
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
||||||
role: piece?.role ?? '',
|
role: piece?.role ?? '',
|
||||||
|
...(piece?.quantity !== undefined && piece.quantity >= 1 ? { quantity: piece.quantity } : {}),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,8 @@ export const sanitizePieces = (pieces: any[]): ComponentModelPiece[] => {
|
|||||||
const rawRole = typeof piece?.role === 'string' ? piece.role.trim() : ''
|
const rawRole = typeof piece?.role === 'string' ? piece.role.trim() : ''
|
||||||
const role = rawRole.length > 0 ? rawRole : undefined
|
const role = rawRole.length > 0 ? rawRole : undefined
|
||||||
|
|
||||||
|
const quantity = typeof piece?.quantity === 'number' && piece.quantity >= 1 ? piece.quantity : undefined
|
||||||
|
|
||||||
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -182,6 +184,9 @@ export const sanitizePieces = (pieces: any[]): ComponentModelPiece[] => {
|
|||||||
if (typePieceLabel) {
|
if (typePieceLabel) {
|
||||||
result.typePieceLabel = typePieceLabel
|
result.typePieceLabel = typePieceLabel
|
||||||
}
|
}
|
||||||
|
if (quantity !== undefined) {
|
||||||
|
result.quantity = quantity
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
.filter((piece): piece is ComponentModelPiece => !!piece)
|
.filter((piece): piece is ComponentModelPiece => !!piece)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface ComponentModelPiece {
|
|||||||
reference?: string
|
reference?: string
|
||||||
familyCode?: string
|
familyCode?: string
|
||||||
role?: string
|
role?: string
|
||||||
|
quantity?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentModelProduct {
|
export interface ComponentModelProduct {
|
||||||
@@ -156,6 +157,7 @@ const validatePiece = (
|
|||||||
const reference = ensureString(value.reference)
|
const reference = ensureString(value.reference)
|
||||||
const familyCode = ensureString(value.familyCode)
|
const familyCode = ensureString(value.familyCode)
|
||||||
const role = ensureString(value.role)
|
const role = ensureString(value.role)
|
||||||
|
const quantity = typeof value.quantity === 'number' && value.quantity >= 1 ? value.quantity : undefined
|
||||||
|
|
||||||
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
||||||
issues.push(`${path}: au moins un identifiant, une famille ou une référence de pièce est requis`)
|
issues.push(`${path}: au moins un identifiant, une famille ou une référence de pièce est requis`)
|
||||||
@@ -168,6 +170,7 @@ const validatePiece = (
|
|||||||
...(reference ? { reference } : {}),
|
...(reference ? { reference } : {}),
|
||||||
...(familyCode ? { familyCode } : {}),
|
...(familyCode ? { familyCode } : {}),
|
||||||
...(role ? { role } : {}),
|
...(role ? { role } : {}),
|
||||||
|
...(quantity ? { quantity } : {}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ export function sanitizePieceDefinition(definition: ComponentModelPiece) {
|
|||||||
typePieceLabel: definition.typePieceLabel ?? null,
|
typePieceLabel: definition.typePieceLabel ?? null,
|
||||||
reference: definition.reference ?? null,
|
reference: definition.reference ?? null,
|
||||||
familyCode: (definition as any).familyCode ?? null,
|
familyCode: (definition as any).familyCode ?? null,
|
||||||
|
quantity: typeof (definition as any).quantity === 'number' ? (definition as any).quantity : null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ export type SelectionEntry = {
|
|||||||
path: string
|
path: string
|
||||||
requirementLabel: string
|
requirementLabel: string
|
||||||
resolvedName: string
|
resolvedName: string
|
||||||
|
quantity?: number
|
||||||
|
_definition?: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StructureSelectionResult = {
|
export type StructureSelectionResult = {
|
||||||
@@ -59,6 +61,8 @@ export function collectStructureSelections(
|
|||||||
path: isNonEmptyString(entry?.path) ? entry.path : `${nodePath}:piece-${index + 1}`,
|
path: isNonEmptyString(entry?.path) ? entry.path : `${nodePath}:piece-${index + 1}`,
|
||||||
requirementLabel: resolvers.resolvePieceLabel(definition),
|
requirementLabel: resolvers.resolvePieceLabel(definition),
|
||||||
resolvedName: catalogPiece?.name || selectedId,
|
resolvedName: catalogPiece?.name || selectedId,
|
||||||
|
quantity: typeof definition?.quantity === 'number' ? definition.quantity : undefined,
|
||||||
|
_definition: definition,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user