update ui machine view
This commit is contained in:
@@ -308,7 +308,63 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Requirement Summary -->
|
||||
<!-- Components Section -->
|
||||
<div class="card bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="card-title">Composants</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-sm gap-2"
|
||||
@click="toggleAllComponents"
|
||||
:title="componentsCollapsed ? 'Déplier tous les composants' : 'Replier tous les composants'"
|
||||
>
|
||||
<IconLucideChevronRight
|
||||
class="w-5 h-5 transition-transform"
|
||||
:class="componentsCollapsed ? 'rotate-0' : 'rotate-90'"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="text-sm">
|
||||
{{ componentsCollapsed ? 'Tout déplier' : 'Tout replier' }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ComponentHierarchy
|
||||
:components="components"
|
||||
:is-edit-mode="isEditMode"
|
||||
:collapse-all="componentsCollapsed"
|
||||
:toggle-token="collapseToggleToken"
|
||||
@update="updateComponent"
|
||||
@edit-piece="updatePieceFromComponent"
|
||||
@custom-field-update="updatePieceCustomField"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Machine Pieces Section -->
|
||||
<div class="card bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="card-title">Pièces de la machine</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<PieceItem
|
||||
v-for="piece in machinePieces"
|
||||
:key="piece.id"
|
||||
:piece="piece"
|
||||
:is-edit-mode="isEditMode"
|
||||
@update="updatePieceInfo"
|
||||
@edit="editPiece"
|
||||
@custom-field-update="updatePieceCustomField"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="componentRequirementGroups.length || pieceRequirementGroups.length"
|
||||
class="card bg-base-100 shadow-lg"
|
||||
@@ -418,373 +474,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Components Section -->
|
||||
<div class="card bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="card-title">Composants</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-sm gap-2"
|
||||
@click="toggleAllComponents"
|
||||
:title="componentsCollapsed ? 'Déplier tous les composants' : 'Replier tous les composants'"
|
||||
>
|
||||
<IconLucideChevronRight
|
||||
class="w-5 h-5 transition-transform"
|
||||
:class="componentsCollapsed ? 'rotate-0' : 'rotate-90'"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="text-sm">
|
||||
{{ componentsCollapsed ? 'Tout déplier' : 'Tout replier' }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ComponentHierarchy
|
||||
:components="components"
|
||||
:is-edit-mode="isEditMode"
|
||||
:collapse-all="componentsCollapsed"
|
||||
:toggle-token="collapseToggleToken"
|
||||
@update="updateComponent"
|
||||
@edit-piece="updatePieceFromComponent"
|
||||
@custom-field-update="updatePieceCustomField"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Machine Pieces Section -->
|
||||
<div class="card bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="card-title">Pièces de la machine</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<PieceItem
|
||||
v-for="piece in machinePieces"
|
||||
:key="piece.id"
|
||||
:piece="piece"
|
||||
:is-edit-mode="isEditMode"
|
||||
@update="updatePieceInfo"
|
||||
@edit="editPiece"
|
||||
@custom-field-update="updatePieceCustomField"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="card bg-base-100 shadow-lg border border-primary/20">
|
||||
<div class="card-body space-y-6">
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h2 class="card-title">
|
||||
{{ skeletonEditorTitle }}
|
||||
</h2>
|
||||
<p class="text-sm text-gray-500">
|
||||
Sélectionnez les composants et pièces à associer à cette machine selon les exigences du type.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-sm"
|
||||
:disabled="skeletonEditor.submitting"
|
||||
@click="changeMachineView('details')"
|
||||
>
|
||||
Fermer
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="skeletonEditor.loading" class="flex justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg"></span>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="!machineHasSkeletonRequirements" class="text-sm text-gray-500">
|
||||
Ce type de machine ne possède pas de squelette structuré.
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="componentRequirements.length" class="space-y-4">
|
||||
<h3 class="text-sm font-semibold text-gray-700">Sélection des composants</h3>
|
||||
|
||||
<div
|
||||
v-for="requirement in componentRequirements"
|
||||
:key="requirement.id"
|
||||
class="border border-base-200 rounded-lg p-4 space-y-3"
|
||||
:id="`component-reconfigure-${requirement.id}`"
|
||||
>
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h4 class="font-medium text-sm">
|
||||
{{ requirement.label || requirement.typeComposant?.name || 'Famille de composants' }}
|
||||
</h4>
|
||||
<p class="text-xs text-gray-500">
|
||||
Type : {{ requirement.typeComposant?.name || 'Non défini' }} · Min : {{ requirement.minCount ?? (requirement.required ? 1 : 0) }}
|
||||
· Max : {{ requirement.maxCount ?? '∞' }} ·
|
||||
{{ requirement.allowNewModels ? 'Nouveaux modèles autorisés' : 'Modèles existants uniquement' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
@click="addComponentSelectionEntry(requirement)"
|
||||
:disabled="requirement.maxCount !== null && getComponentRequirementEntries(requirement.id).length >= requirement.maxCount"
|
||||
>
|
||||
<IconLucidePlus class="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="getComponentRequirementEntries(requirement.id).length === 0" class="text-xs text-gray-500">
|
||||
Aucun composant sélectionné pour ce groupe.
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(entry, entryIndex) in getComponentRequirementEntries(requirement.id)"
|
||||
:key="`${requirement.id}-${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é :
|
||||
{{ resolveComponentRequirementTypeLabel(requirement, entry) }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-square btn-xs btn-error"
|
||||
@click="removeComponentSelectionEntry(requirement.id, entryIndex)"
|
||||
>
|
||||
<IconLucideX class="w-4 h-4" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Catégorie de composant</span>
|
||||
</label>
|
||||
<select
|
||||
class="select select-bordered select-xs md:select-sm"
|
||||
:value="entry.typeComposantId || requirement.typeComposantId || ''"
|
||||
@change="setComponentRequirementType(requirement.id, entryIndex, ($event.target && $event.target.value) || '')"
|
||||
>
|
||||
<option value="">
|
||||
{{ requirement.typeComposant?.name ? `Type du requirement (${requirement.typeComposant.name})` : 'Suivre le requirement' }}
|
||||
</option>
|
||||
<option
|
||||
v-for="type in componentTypeOptions"
|
||||
:key="type.id"
|
||||
:value="type.id"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Nom du composant</span>
|
||||
</label>
|
||||
<input
|
||||
v-model="entry.definition.name"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="Nom du composant"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Référence (optionnel)</span>
|
||||
</label>
|
||||
<input
|
||||
v-model="entry.definition.reference"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="Référence du composant"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Constructeur (optionnel)</span>
|
||||
</label>
|
||||
<ConstructeurSelect
|
||||
class="w-full"
|
||||
:model-value="entry.definition.constructeurId || null"
|
||||
placeholder="Sélectionner un constructeur"
|
||||
@update:modelValue="(value) => setComponentRequirementConstructeur(requirement.id, entryIndex, value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Prix (optionnel)</span>
|
||||
</label>
|
||||
<input
|
||||
v-model.number="entry.definition.prix"
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="0.00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="pieceRequirements.length" class="space-y-4">
|
||||
<h3 class="text-sm font-semibold text-gray-700">Sélection des pièces principales</h3>
|
||||
|
||||
<div
|
||||
v-for="requirement in pieceRequirements"
|
||||
:key="requirement.id"
|
||||
class="border border-base-200 rounded-lg p-4 space-y-3"
|
||||
:id="`piece-reconfigure-${requirement.id}`"
|
||||
>
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h4 class="font-medium text-sm">
|
||||
{{ requirement.label || requirement.typePiece?.name || 'Groupe de pièces' }}
|
||||
</h4>
|
||||
<p class="text-xs text-gray-500">
|
||||
Type : {{ requirement.typePiece?.name || 'Non défini' }} · Min : {{ requirement.minCount ?? (requirement.required ? 1 : 0) }}
|
||||
· Max : {{ requirement.maxCount ?? '∞' }} ·
|
||||
{{ requirement.allowNewModels ? 'Nouveaux modèles autorisés' : 'Modèles existants uniquement' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline"
|
||||
@click="addPieceSelectionEntry(requirement)"
|
||||
:disabled="requirement.maxCount !== null && getPieceRequirementEntries(requirement.id).length >= requirement.maxCount"
|
||||
>
|
||||
<IconLucidePlus class="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="getPieceRequirementEntries(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 getPieceRequirementEntries(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é :
|
||||
{{ resolvePieceRequirementTypeLabel(requirement, entry) }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-square btn-xs btn-error"
|
||||
@click="removePieceSelectionEntry(requirement.id, entryIndex)"
|
||||
>
|
||||
<IconLucideX class="w-4 h-4" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Catégorie de pièce</span>
|
||||
</label>
|
||||
<select
|
||||
class="select select-bordered select-xs md:select-sm"
|
||||
:value="entry.typePieceId || requirement.typePieceId || ''"
|
||||
@change="setPieceRequirementType(requirement.id, entryIndex, ($event.target && $event.target.value) || '')"
|
||||
>
|
||||
<option value="">
|
||||
{{ requirement.typePiece?.name ? `Type du requirement (${requirement.typePiece.name})` : 'Suivre le requirement' }}
|
||||
</option>
|
||||
<option
|
||||
v-for="type in pieceTypeOptions"
|
||||
:key="type.id"
|
||||
:value="type.id"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Nom de la pièce</span>
|
||||
</label>
|
||||
<input
|
||||
v-model="entry.definition.name"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="Nom de la pièce"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Référence (optionnel)</span>
|
||||
</label>
|
||||
<input
|
||||
v-model="entry.definition.reference"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="Référence de la pièce"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Constructeur (optionnel)</span>
|
||||
</label>
|
||||
<ConstructeurSelect
|
||||
class="w-full"
|
||||
:model-value="entry.definition.constructeurId || null"
|
||||
placeholder="Sélectionner un constructeur"
|
||||
@update:modelValue="(value) => setPieceRequirementConstructeur(requirement.id, entryIndex, value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text text-xs">Prix (optionnel)</span>
|
||||
</label>
|
||||
<input
|
||||
v-model.number="entry.definition.prix"
|
||||
type="number"
|
||||
min="0"
|
||||
step="0.01"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="0.00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="flex flex-wrap justify-end gap-2 pt-2 border-t border-base-200">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost"
|
||||
:disabled="skeletonEditor.submitting"
|
||||
@click="changeMachineView('details')"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
:class="{ loading: skeletonEditor.submitting }"
|
||||
@click="saveSkeletonConfiguration"
|
||||
>
|
||||
Sauvegarder la configuration
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -1585,12 +1274,6 @@ const machineViewTitle = computed(() => {
|
||||
return isEditMode.value ? 'Modification de la machine' : 'Détails de la machine'
|
||||
})
|
||||
|
||||
const skeletonEditorTitle = computed(() =>
|
||||
skeletonEditor.open
|
||||
? 'Modification des éléments du squelette'
|
||||
: 'Éléments du squelette'
|
||||
)
|
||||
|
||||
// Gestion du pliage global des composants
|
||||
const componentsCollapsed = ref(true)
|
||||
const collapseToggleToken = ref(0)
|
||||
|
||||
Reference in New Issue
Block a user