Files
Inventory/app/components/ComponentItem.vue
Matthieu 36a44848d2 feat: Composants d'affichage des machines et composants
- ComponentHierarchy.vue : Affichage hiérarchique des composants
- ComponentItem.vue : Affichage d'un composant individuel
- CustomFieldsDisplay.vue : Affichage des champs personnalisés
- PieceItem.vue : Affichage des pièces de machines
- Support de l'affichage en lecture seule et édition
- Gestion des relations parent-enfant entre composants
2025-07-30 08:18:30 +02:00

268 lines
9.1 KiB
Vue

<template>
<div class="space-y-4">
<!-- Component Header -->
<div class="flex items-center justify-between p-4 bg-base-200 rounded-lg">
<div class="flex-1">
<h3 class="text-lg font-semibold">{{ component.name }}</h3>
<div class="flex flex-wrap gap-2 mt-2">
<span v-if="component.reference" class="badge badge-outline badge-sm">
{{ component.reference }}
</span>
<span v-if="component.prestataire" class="badge badge-outline badge-sm">
{{ component.prestataire }}
</span>
<span v-if="component.emplacement" class="badge badge-outline badge-sm">
{{ component.emplacement }}
</span>
<span v-if="component.prix" class="badge badge-primary badge-sm">
{{ component.prix }}
</span>
</div>
</div>
</div>
<!-- Component Info Display - Editable or Read-only -->
<div class="p-4 bg-base-100 border border-gray-200 rounded-lg">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div class="form-control">
<label class="label">
<span class="label-text font-medium">Nom</span>
</label>
<input
v-if="isEditMode"
v-model="component.name"
type="text"
class="input input-bordered input-sm"
@blur="updateComponent"
/>
<div v-else class="input input-bordered input-sm bg-base-200">
{{ component.name }}
</div>
</div>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">Référence</span>
</label>
<input
v-if="isEditMode"
v-model="component.reference"
type="text"
class="input input-bordered input-sm"
@blur="updateComponent"
/>
<div v-else class="input input-bordered input-sm bg-base-200">
{{ component.reference || 'Non définie' }}
</div>
</div>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">Prestataire</span>
</label>
<input
v-if="isEditMode"
v-model="component.prestataire"
type="text"
class="input input-bordered input-sm"
@blur="updateComponent"
/>
<div v-else class="input input-bordered input-sm bg-base-200">
{{ component.prestataire || 'Non défini' }}
</div>
</div>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">Emplacement</span>
</label>
<input
v-if="isEditMode"
v-model="component.emplacement"
type="text"
class="input input-bordered input-sm"
@blur="updateComponent"
/>
<div v-else class="input input-bordered input-sm bg-base-200">
{{ component.emplacement || 'Non défini' }}
</div>
</div>
<div class="form-control">
<label class="label">
<span class="label-text font-medium">Prix</span>
</label>
<input
v-if="isEditMode"
v-model="component.prix"
type="number"
step="0.01"
class="input input-bordered input-sm"
@blur="updateComponent"
/>
<div v-else class="input input-bordered input-sm bg-base-200">
{{ component.prix ? `${component.prix}` : 'Non défini' }}
</div>
</div>
</div>
<!-- Custom Fields Display - Editable or Read-only -->
<div v-if="component.customFields && component.customFields.length > 0" class="mt-4 pt-4 border-t border-gray-200">
<h4 class="font-semibold text-sm text-gray-700 mb-3">Champs personnalisés</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div
v-for="field in component.customFields"
:key="field.id"
class="form-control"
>
<label class="label">
<span class="label-text text-sm">{{ field.name }}</span>
<span v-if="field.required" class="label-text-alt text-error">*</span>
</label>
<!-- Mode édition -->
<template v-if="isEditMode">
<!-- Champ de type TEXT -->
<input
v-if="field.type === 'text'"
v-model="field.value"
type="text"
:placeholder="field.defaultValue || ''"
class="input input-bordered input-sm"
:required="field.required"
@blur="updateComponentCustomField(field)"
/>
<!-- Champ de type NUMBER -->
<input
v-else-if="field.type === 'number'"
v-model="field.value"
type="number"
:placeholder="field.defaultValue || ''"
class="input input-bordered input-sm"
:required="field.required"
@blur="updateComponentCustomField(field)"
/>
<!-- Champ de type SELECT -->
<select
v-else-if="field.type === 'select'"
v-model="field.value"
class="select select-bordered select-sm"
:required="field.required"
@change="updateComponentCustomField(field)"
>
<option value="">{{ field.defaultValue || 'Sélectionner...' }}</option>
<option
v-for="option in field.options"
:key="option"
:value="option"
>
{{ option }}
</option>
</select>
<!-- Champ de type BOOLEAN -->
<div v-else-if="field.type === 'boolean'" class="flex items-center gap-2">
<input
v-model="field.value"
type="checkbox"
class="checkbox checkbox-sm"
:checked="field.value === 'true'"
@change="updateComponentCustomField(field)"
/>
<span class="text-sm">{{ field.value === 'true' ? 'Oui' : 'Non' }}</span>
</div>
<!-- Champ de type DATE -->
<input
v-else-if="field.type === 'date'"
v-model="field.value"
type="date"
:placeholder="field.defaultValue || ''"
class="input input-bordered input-sm"
:required="field.required"
@blur="updateComponentCustomField(field)"
/>
</template>
<!-- Mode lecture seule -->
<template v-else>
<div class="input input-bordered input-sm bg-base-200">
{{ field.value || field.defaultValue || 'Non défini' }}
</div>
</template>
</div>
</div>
</div>
</div>
<!-- Component Pieces -->
<div v-if="component.pieces && component.pieces.length > 0" class="space-y-2">
<h4 class="font-semibold text-gray-700">Pièces du composant</h4>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
<PieceItem
v-for="piece in component.pieces"
:key="piece.id"
:piece="piece"
:is-edit-mode="isEditMode"
@update="updatePiece"
@edit="editPiece"
@custom-field-update="updatePieceCustomField"
/>
</div>
</div>
<!-- Sub Components -->
<div v-if="component.subComponents && component.subComponents.length > 0" class="space-y-3">
<h4 class="font-semibold text-gray-700">Sous-composants</h4>
<div class="space-y-3 pl-4 border-l-2 border-gray-200">
<ComponentItem
v-for="subComponent in component.subComponents"
:key="subComponent.id"
:component="subComponent"
:is-edit-mode="isEditMode"
@update="$emit('update', $event)"
@edit-piece="$emit('edit-piece', $event)"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import PieceItem from './PieceItem.vue'
const props = defineProps({
component: {
type: Object,
required: true
},
isEditMode: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update', 'edit-piece'])
// Methods
const updateComponent = () => {
emit('update', props.component)
}
const updateComponentCustomField = (field) => {
// Mettre à jour le champ personnalisé du composant
emit('update', props.component)
}
const updatePiece = (updatedPiece) => {
emit('edit-piece', updatedPiece)
}
const editPiece = (piece) => {
emit('edit-piece', piece)
}
const updatePieceCustomField = (fieldUpdate) => {
// Forward to parent
emit('edit-piece', { ...fieldUpdate, type: 'custom-field-update' })
}
</script>