feat: Composants de formulaire pour les types de machines

- TypeComponentForm.vue : Formulaire pour ajouter des composants avec hiérarchie
- TypeMachinePieceForm.vue : Formulaire pour ajouter des pièces principales
- Support des champs personnalisés avec différents types (text, number, select, boolean, date)
- Gestion des sous-composants et pièces imbriquées
- Validation et gestion des options pour les champs de type SELECT
This commit is contained in:
Matthieu
2025-07-30 08:17:33 +02:00
parent 9fb0353442
commit ca44a78aad
2 changed files with 922 additions and 0 deletions

View File

@@ -0,0 +1,698 @@
<template>
<div class="space-y-4">
<div v-for="(component, index) in components" :key="index" class="border border-gray-200 rounded-lg p-4 bg-gray-50">
<div class="flex items-center justify-between mb-3">
<h5 class="text-sm font-medium">Nouveau composant {{ index + 1 }}</h5>
<button
type="button"
@click="removeComponent(index)"
class="btn btn-square btn-error btn-sm"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<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">Nom du composant</span>
</label>
<input
v-model="component.name"
type="text"
placeholder="Nom du composant"
class="input input-bordered input-sm"
required
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Référence</span>
</label>
<input
v-model="component.reference"
type="text"
placeholder="Référence"
class="input input-bordered input-sm"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Prestataire</span>
</label>
<input
v-model="component.prestataire"
type="text"
placeholder="Prestataire"
class="input input-bordered input-sm"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Emplacement</span>
</label>
<input
v-model="component.emplacement"
type="text"
placeholder="Emplacement"
class="input input-bordered input-sm"
/>
</div>
</div>
<!-- Champs personnalisés du composant -->
<div class="mb-4">
<div class="flex items-center gap-2 mb-2">
<span class="text-xs font-medium text-gray-600">Champs personnalisés du composant :</span>
<button
type="button"
@click="addComponentCustomField(component)"
class="btn btn-xs btn-outline"
>
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter champ
</button>
</div>
<div class="space-y-2">
<div
v-for="(field, fieldIndex) in component.customFields"
:key="fieldIndex"
class="border border-gray-200 rounded p-2 bg-white"
>
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-medium">Champ personnalisé {{ fieldIndex + 1 }}</span>
<button
type="button"
@click="removeComponentCustomField(component, fieldIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
<div>
<input
v-model="field.name"
type="text"
placeholder="Nom du champ"
class="input input-bordered input-xs w-full"
/>
</div>
<div>
<select v-model="field.type" class="select select-bordered select-xs w-full">
<option value="">Type</option>
<option value="text">Texte</option>
<option value="number">Nombre</option>
<option value="select">Liste</option>
<option value="boolean">Oui/Non</option>
<option value="date">Date</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2 mt-2">
<div class="flex items-center gap-2">
<input
v-model="field.required"
type="checkbox"
class="checkbox checkbox-xs"
/>
<span class="text-xs">Obligatoire</span>
</div>
<div>
<input
v-model="field.defaultValue"
type="text"
placeholder="Valeur par défaut"
class="input input-bordered input-xs w-full"
/>
</div>
</div>
<!-- Options pour les champs de type SELECT -->
<div v-if="field.type === 'select'" class="mt-2">
<textarea
v-model="field.optionsText"
placeholder="Option 1&#10;Option 2&#10;Option 3"
class="textarea textarea-bordered textarea-xs w-full h-16"
@input="updateComponentFieldOptions(component, fieldIndex)"
></textarea>
</div>
</div>
</div>
</div>
<!-- Pièces du nouveau composant -->
<div class="mb-4">
<div class="flex items-center gap-2 mb-2">
<span class="text-xs font-medium text-gray-600">Pièces du composant :</span>
<button
type="button"
@click="addComponentPiece(component)"
class="btn btn-xs btn-outline"
>
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter pièce
</button>
</div>
<div class="space-y-2">
<div
v-for="(piece, pieceIndex) in component.pieces"
:key="pieceIndex"
class="border border-gray-200 rounded p-2 bg-white"
>
<div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-2">
<svg class="w-3 h-3 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
<input
v-model="component.pieces[pieceIndex].name"
type="text"
:placeholder="`Pièce ${pieceIndex + 1}`"
class="input input-bordered input-xs flex-1"
/>
</div>
<div class="flex gap-1">
<button
type="button"
@click="addCustomFieldToPiece('component', component, pieceIndex)"
class="btn btn-xs btn-ghost"
>
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
</button>
<button
type="button"
@click="removeComponentPiece(component, pieceIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
</div>
<!-- Champs personnalisés de cette pièce -->
<div v-if="piece.customFields && piece.customFields.length > 0" class="mt-2 ml-4">
<div class="space-y-1">
<div
v-for="(field, fieldIndex) in piece.customFields"
:key="fieldIndex"
class="border border-gray-100 rounded p-1 bg-gray-50"
>
<div class="flex items-center justify-between mb-1">
<span class="text-xs">Champ {{ fieldIndex + 1 }}</span>
<button
type="button"
@click="removeCustomFieldFromPiece('component', component, fieldIndex, pieceIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-2 gap-1">
<input
v-model="field.name"
type="text"
placeholder="Nom"
class="input input-bordered input-xs"
/>
<select v-model="field.type" class="select select-bordered select-xs">
<option value="">Type</option>
<option value="text">Texte</option>
<option value="number">Nombre</option>
<option value="select">Liste</option>
<option value="boolean">Oui/Non</option>
<option value="date">Date</option>
</select>
</div>
<div class="grid grid-cols-2 gap-1 mt-1">
<div class="flex items-center gap-1">
<input
v-model="field.required"
type="checkbox"
class="checkbox checkbox-xs"
/>
<span class="text-xs">Obligatoire</span>
</div>
<input
v-model="field.defaultValue"
type="text"
placeholder="Défaut"
class="input input-bordered input-xs"
/>
</div>
<!-- Options pour les champs de type SELECT -->
<div v-if="field.type === 'select'" class="mt-1">
<textarea
v-model="field.optionsText"
placeholder="Option 1&#10;Option 2&#10;Option 3"
class="textarea textarea-bordered textarea-xs w-full h-12"
@input="updatePieceFieldOptions('component', pieceIndex, fieldIndex, component)"
></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Sous-composants -->
<div class="ml-6 space-y-2">
<div class="flex items-center gap-2 mb-2">
<span class="text-xs font-medium text-gray-600">Sous-composants :</span>
<button
type="button"
@click="addSubComponent(component)"
class="btn btn-xs btn-outline"
>
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter
</button>
</div>
<div
v-for="(subComponent, subIndex) in component.subComponents"
:key="subIndex"
class="border border-gray-200 rounded p-3 bg-white"
>
<div class="flex items-center gap-2 mb-2">
<svg class="w-3 h-3 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<input
v-model="subComponent.name"
type="text"
:placeholder="`Sous-composant ${subIndex + 1}`"
class="input input-bordered input-xs flex-1"
required
/>
<button
type="button"
@click="removeSubComponent(component, subIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Champs personnalisés du sous-composant -->
<div class="mb-2">
<div class="flex items-center gap-2 mb-1">
<span class="text-xs text-gray-500">Champs personnalisés :</span>
<button
type="button"
@click="addSubComponentCustomField(subComponent)"
class="btn btn-xs btn-ghost"
>
<svg class="w-2 h-2 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
+
</button>
</div>
<div class="space-y-1">
<div
v-for="(field, fieldIndex) in subComponent.customFields"
:key="fieldIndex"
class="border border-gray-100 rounded p-1 bg-gray-50"
>
<div class="flex items-center justify-between mb-1">
<span class="text-xs">Champ {{ fieldIndex + 1 }}</span>
<button
type="button"
@click="removeSubComponentCustomField(subComponent, fieldIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-2 gap-1">
<input
v-model="field.name"
type="text"
placeholder="Nom"
class="input input-bordered input-xs"
/>
<select v-model="field.type" class="select select-bordered select-xs">
<option value="">Type</option>
<option value="text">Texte</option>
<option value="number">Nombre</option>
<option value="select">Liste</option>
<option value="boolean">Oui/Non</option>
<option value="date">Date</option>
</select>
</div>
<div class="grid grid-cols-2 gap-1 mt-1">
<div class="flex items-center gap-1">
<input
v-model="field.required"
type="checkbox"
class="checkbox checkbox-xs"
/>
<span class="text-xs">Obligatoire</span>
</div>
<input
v-model="field.defaultValue"
type="text"
placeholder="Défaut"
class="input input-bordered input-xs"
/>
</div>
</div>
</div>
</div>
<!-- Pièces du sous-composant -->
<div class="mb-2">
<div class="flex items-center gap-2 mb-1">
<span class="text-xs text-gray-500">Pièces :</span>
<button
type="button"
@click="addSubComponentPiece(subComponent)"
class="btn btn-xs btn-ghost"
>
<svg class="w-2 h-2 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
+
</button>
</div>
<div class="space-y-1">
<div
v-for="(piece, pieceIndex) in subComponent.pieces"
:key="pieceIndex"
class="border border-gray-100 rounded p-1 bg-gray-50"
>
<div class="flex items-center justify-between mb-1">
<div class="flex items-center gap-1">
<svg class="w-2 h-2 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
<input
v-model="subComponent.pieces[pieceIndex].name"
type="text"
:placeholder="`Pièce ${pieceIndex + 1}`"
class="input input-bordered input-xs flex-1"
/>
</div>
<div class="flex gap-1">
<button
type="button"
@click="addCustomFieldToPiece('subComponent', subComponent, pieceIndex)"
class="btn btn-xs btn-ghost"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
</button>
<button
type="button"
@click="removeSubComponentPiece(subComponent, pieceIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
</div>
<!-- Champs personnalisés de cette pièce -->
<div v-if="piece.customFields && piece.customFields.length > 0" class="mt-1 ml-3">
<div class="space-y-1">
<div
v-for="(field, fieldIndex) in piece.customFields"
:key="fieldIndex"
class="border border-gray-50 rounded p-1 bg-gray-25"
>
<div class="flex items-center justify-between mb-1">
<span class="text-xs">Champ {{ fieldIndex + 1 }}</span>
<button
type="button"
@click="removeCustomFieldFromPiece('subComponent', subComponent, fieldIndex, pieceIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-2 h-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-2 gap-1">
<input
v-model="field.name"
type="text"
placeholder="Nom"
class="input input-bordered input-xs"
/>
<select v-model="field.type" class="select select-bordered select-xs">
<option value="">Type</option>
<option value="text">Texte</option>
<option value="number">Nombre</option>
<option value="select">Liste</option>
<option value="boolean">Oui/Non</option>
<option value="date">Date</option>
</select>
</div>
<div class="grid grid-cols-2 gap-1 mt-1">
<div class="flex items-center gap-1">
<input
v-model="field.required"
type="checkbox"
class="checkbox checkbox-xs"
/>
<span class="text-xs">Obligatoire</span>
</div>
<input
v-model="field.defaultValue"
type="text"
placeholder="Défaut"
class="input input-bordered input-xs"
/>
</div>
<!-- Options pour les champs de type SELECT -->
<div v-if="field.type === 'select'" class="mt-1">
<textarea
v-model="field.optionsText"
placeholder="Option 1&#10;Option 2&#10;Option 3"
class="textarea textarea-bordered textarea-xs w-full h-10"
@input="updatePieceFieldOptions('subComponent', pieceIndex, fieldIndex, subComponent)"
></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<button
type="button"
@click="addComponent"
class="btn btn-outline btn-sm"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter un composant
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
modelValue: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['update:modelValue'])
const components = ref(props.modelValue)
// Méthodes pour les composants
const addComponent = () => {
components.value.push({
name: '',
reference: '',
prestataire: '',
emplacement: '',
prix: null,
pieces: [],
customFields: [],
subComponents: []
})
emit('update:modelValue', components.value)
}
const removeComponent = (index) => {
components.value.splice(index, 1)
emit('update:modelValue', components.value)
}
const addComponentPiece = (component) => {
component.pieces.push({
name: '',
reference: '',
prestataire: '',
emplacement: '',
prix: null,
customFields: []
})
}
const removeComponentPiece = (component, index) => {
component.pieces.splice(index, 1)
}
const addComponentCustomField = (component) => {
if (!component.customFields) {
component.customFields = []
}
component.customFields.push({
name: '',
type: '',
required: false,
defaultValue: '',
optionsText: ''
})
}
const removeComponentCustomField = (component, index) => {
component.customFields.splice(index, 1)
}
const updateComponentFieldOptions = (component, index) => {
if (component.customFields[index]) {
component.customFields[index].optionsText = component.customFields[index].optionsText.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
}
}
// Méthodes pour les sous-composants
const addSubComponent = (component) => {
if (!component.subComponents) {
component.subComponents = []
}
component.subComponents.push({
name: '',
subComponents: [],
pieces: [{ name: '', customFields: [] }],
customFields: []
})
}
const removeSubComponent = (component, index) => {
component.subComponents.splice(index, 1)
}
const addSubComponentPiece = (subComponent) => {
subComponent.pieces.push({ name: '', customFields: [] })
}
const removeSubComponentPiece = (subComponent, index) => {
subComponent.pieces.splice(index, 1)
}
const addSubComponentCustomField = (subComponent) => {
if (!subComponent.customFields) {
subComponent.customFields = []
}
subComponent.customFields.push({
name: '',
type: '',
required: false,
defaultValue: '',
optionsText: ''
})
}
const removeSubComponentCustomField = (subComponent, index) => {
subComponent.customFields.splice(index, 1)
}
// Méthodes pour les champs personnalisés des pièces
const addCustomFieldToPiece = (sourceType, sourceIndex, pieceIndex) => {
if (sourceType === 'component') {
if (!sourceIndex.pieces[pieceIndex].customFields) {
sourceIndex.pieces[pieceIndex].customFields = []
}
sourceIndex.pieces[pieceIndex].customFields.push({
name: '',
type: '',
required: false,
defaultValue: '',
optionsText: ''
})
} else if (sourceType === 'subComponent') {
if (!sourceIndex.pieces[pieceIndex].customFields) {
sourceIndex.pieces[pieceIndex].customFields = []
}
sourceIndex.pieces[pieceIndex].customFields.push({
name: '',
type: '',
required: false,
defaultValue: '',
optionsText: ''
})
}
}
const removeCustomFieldFromPiece = (sourceType, sourceIndex, fieldIndex, pieceIndex) => {
if (sourceType === 'component') {
if (sourceIndex.pieces[pieceIndex].customFields) {
sourceIndex.pieces[pieceIndex].customFields.splice(fieldIndex, 1)
}
} else if (sourceType === 'subComponent') {
if (sourceIndex.pieces[pieceIndex].customFields) {
sourceIndex.pieces[pieceIndex].customFields.splice(fieldIndex, 1)
}
}
}
const updatePieceFieldOptions = (sourceType, sourceIndex, fieldIndex, component) => {
if (sourceType === 'component') {
if (component && component.pieces[sourceIndex].customFields[fieldIndex]) {
component.pieces[sourceIndex].customFields[fieldIndex].optionsText = component.pieces[sourceIndex].customFields[fieldIndex].optionsText.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
}
} else if (sourceType === 'subComponent') {
if (component && component.pieces[sourceIndex].customFields[fieldIndex]) {
component.pieces[sourceIndex].customFields[fieldIndex].optionsText = component.pieces[sourceIndex].customFields[fieldIndex].optionsText.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
}
}
}
</script>

View File

@@ -0,0 +1,224 @@
<template>
<div class="space-y-4">
<div v-for="(piece, index) in pieces" :key="index" class="border border-gray-200 rounded-lg p-4 bg-gray-50">
<div class="flex items-center justify-between mb-3">
<h5 class="text-sm font-medium">Nouvelle pièce {{ index + 1 }}</h5>
<button
type="button"
@click="removePiece(index)"
class="btn btn-square btn-error btn-sm"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">Nom de la pièce</span>
</label>
<input
v-model="piece.name"
type="text"
placeholder="Nom de la pièce"
class="input input-bordered input-sm"
required
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Référence</span>
</label>
<input
v-model="piece.reference"
type="text"
placeholder="Référence"
class="input input-bordered input-sm"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Prestataire</span>
</label>
<input
v-model="piece.prestataire"
type="text"
placeholder="Prestataire"
class="input input-bordered input-sm"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Emplacement</span>
</label>
<input
v-model="piece.emplacement"
type="text"
placeholder="Emplacement"
class="input input-bordered input-sm"
/>
</div>
</div>
<!-- Champs personnalisés de cette pièce -->
<div v-if="piece.customFields && piece.customFields.length > 0" class="mt-4">
<h6 class="text-xs font-medium text-gray-600 mb-2">Champs personnalisés de cette pièce :</h6>
<div class="space-y-2">
<div
v-for="(field, fieldIndex) in piece.customFields"
:key="fieldIndex"
class="border border-gray-200 rounded p-2 bg-white"
>
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-medium">Champ {{ fieldIndex + 1 }}</span>
<button
type="button"
@click="removeCustomField(index, fieldIndex)"
class="btn btn-square btn-error btn-xs"
>
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
<div>
<input
v-model="field.name"
type="text"
placeholder="Nom du champ"
class="input input-bordered input-xs w-full"
/>
</div>
<div>
<select v-model="field.type" class="select select-bordered select-xs w-full">
<option value="">Type</option>
<option value="text">Texte</option>
<option value="number">Nombre</option>
<option value="select">Liste</option>
<option value="boolean">Oui/Non</option>
<option value="date">Date</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2 mt-2">
<div class="flex items-center gap-2">
<input
v-model="field.required"
type="checkbox"
class="checkbox checkbox-xs"
/>
<span class="text-xs">Obligatoire</span>
</div>
<div>
<input
v-model="field.defaultValue"
type="text"
placeholder="Valeur par défaut"
class="input input-bordered input-xs w-full"
/>
</div>
</div>
<!-- Options pour les champs de type SELECT -->
<div v-if="field.type === 'select'" class="mt-2">
<textarea
v-model="field.optionsText"
placeholder="Option 1&#10;Option 2&#10;Option 3"
class="textarea textarea-bordered textarea-xs w-full h-16"
@input="updateFieldOptions(index, fieldIndex)"
></textarea>
</div>
</div>
</div>
</div>
<!-- Bouton pour ajouter des champs personnalisés -->
<div class="mt-3">
<button
type="button"
@click="addCustomField(index)"
class="btn btn-outline btn-sm"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter champs personnalisés
</button>
</div>
</div>
<button
type="button"
@click="addPiece"
class="btn btn-outline btn-sm"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Ajouter une pièce de machine
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
modelValue: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['update:modelValue'])
const pieces = ref(props.modelValue)
// Méthodes pour les pièces
const addPiece = () => {
pieces.value.push({
name: '',
reference: '',
prestataire: '',
emplacement: '',
prix: null,
customFields: []
})
emit('update:modelValue', pieces.value)
}
const removePiece = (index) => {
pieces.value.splice(index, 1)
emit('update:modelValue', pieces.value)
}
const addCustomField = (pieceIndex) => {
if (!pieces.value[pieceIndex].customFields) {
pieces.value[pieceIndex].customFields = []
}
pieces.value[pieceIndex].customFields.push({
name: '',
type: '',
required: false,
defaultValue: '',
optionsText: ''
})
}
const removeCustomField = (pieceIndex, fieldIndex) => {
if (pieces.value[pieceIndex].customFields) {
pieces.value[pieceIndex].customFields.splice(fieldIndex, 1)
}
}
const updateFieldOptions = (pieceIndex, fieldIndex) => {
if (pieces.value[pieceIndex].customFields[fieldIndex]) {
pieces.value[pieceIndex].customFields[fieldIndex].optionsText = pieces.value[pieceIndex].customFields[fieldIndex].optionsText.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
}
}
</script>