Extract useMachineCreatePage composable and 5 preview/selector components from machines/new.vue, reducing it from 1231 to 196 LOC. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
131 lines
4.7 KiB
Vue
131 lines
4.7 KiB
Vue
<template>
|
|
<div v-if="requirements?.length" class="space-y-4">
|
|
<h4 class="text-sm font-semibold">
|
|
Sélection des pièces principales
|
|
</h4>
|
|
|
|
<div
|
|
v-for="requirement in requirements"
|
|
:id="`piece-group-${requirement.id}`"
|
|
:key="requirement.id"
|
|
class="border border-base-200 rounded-lg p-4 space-y-3"
|
|
>
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div>
|
|
<h5 class="font-medium text-sm">
|
|
{{ requirement.label || requirement.typePiece?.name || 'Groupe de pièces' }}
|
|
</h5>
|
|
<p class="text-xs text-gray-500">
|
|
Type : {{ requirement.typePiece?.name || 'Non défini' }} · Min : {{ requirement.minCount ?? (requirement.required ? 1 : 0) }}
|
|
· Max : {{ requirement.maxCount ?? '∞' }}
|
|
</p>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-outline"
|
|
:disabled="requirement.maxCount !== null && getEntries(requirement.id).length >= requirement.maxCount"
|
|
@click="$emit('add-entry', requirement)"
|
|
>
|
|
<IconLucidePlus class="w-4 h-4 mr-2" aria-hidden="true" />
|
|
Ajouter
|
|
</button>
|
|
</div>
|
|
|
|
<div v-if="getEntries(requirement.id).length === 0" class="text-xs text-gray-500">
|
|
Aucune pièce sélectionnée pour ce groupe.
|
|
</div>
|
|
|
|
<div
|
|
v-for="(entry, entryIndex) in getEntries(requirement.id)"
|
|
:key="`${requirement.id}-piece-${entryIndex}`"
|
|
class="bg-base-200/60 rounded-md p-3 space-y-4"
|
|
>
|
|
<div class="flex flex-wrap items-center justify-between gap-2 text-xs text-gray-500">
|
|
<span>
|
|
Type appliqué :
|
|
{{ resolveTypeLabel(requirement, entry) }}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
class="btn btn-square btn-xs btn-error"
|
|
@click="$emit('remove-entry', requirement.id, entryIndex)"
|
|
>
|
|
<IconLucideX class="w-4 h-4" aria-hidden="true" />
|
|
</button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 gap-3">
|
|
<div class="space-y-2">
|
|
<div class="form-control">
|
|
<label class="label">
|
|
<span class="label-text text-xs">Pièce existante</span>
|
|
</label>
|
|
<SearchSelect
|
|
:model-value="entry.pieceId || ''"
|
|
:options="getOptions(requirement, entry, entryIndex)"
|
|
:loading="loading || pieceLoadingByKey[getPieceKey(requirement, entryIndex)]"
|
|
size="sm"
|
|
placeholder="Rechercher une pièce…"
|
|
empty-text="Aucune pièce disponible"
|
|
:option-label="optionLabel"
|
|
:option-description="optionDescription"
|
|
@search="(term: string) => $emit('search', requirement, entryIndex, term)"
|
|
@update:modelValue="$emit('set-piece', requirement, entryIndex, $event || '')"
|
|
/>
|
|
</div>
|
|
<p
|
|
v-if="getOptions(requirement, entry, entryIndex).length === 0"
|
|
class="text-xs text-error"
|
|
>
|
|
Aucune pièce disponible pour cette famille.
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
v-if="entry.pieceId"
|
|
class="bg-base-300/60 rounded-md p-3 text-xs text-gray-600 space-y-1"
|
|
>
|
|
<div class="font-medium">
|
|
{{ findById(entry.pieceId)?.name || "Pièce" }}
|
|
</div>
|
|
<div>
|
|
Référence : {{ findById(entry.pieceId)?.reference || "—" }}
|
|
</div>
|
|
<div>
|
|
Fournisseur :
|
|
{{ findById(entry.pieceId)?.constructeur?.name || findById(entry.pieceId)?.constructeurName || "—" }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import SearchSelect from '~/components/common/SearchSelect.vue'
|
|
import IconLucidePlus from '~icons/lucide/plus'
|
|
import IconLucideX from '~icons/lucide/x'
|
|
|
|
defineProps<{
|
|
requirements: any[]
|
|
loading: boolean
|
|
pieceLoadingByKey: Record<string, boolean>
|
|
getEntries: (requirementId: string) => any[]
|
|
getOptions: (requirement: any, entry: any, entryIndex: number) => any[]
|
|
getPieceKey: (requirement: any, entryIndex: number) => string
|
|
resolveTypeLabel: (requirement: any, entry: any) => string
|
|
findById: (id: string) => any
|
|
optionLabel: (item: any) => string
|
|
optionDescription: (item: any) => string
|
|
}>()
|
|
|
|
defineEmits<{
|
|
'add-entry': [requirement: any]
|
|
'remove-entry': [requirementId: string, entryIndex: number]
|
|
'set-piece': [requirement: any, entryIndex: number, pieceId: string]
|
|
'search': [requirement: any, entryIndex: number, term: string]
|
|
}>()
|
|
</script>
|