163 lines
6.4 KiB
Vue
163 lines
6.4 KiB
Vue
<template>
|
|
<div class="space-y-3 rounded-lg border border-base-200 bg-base-200/40 p-4">
|
|
<div class="flex items-center justify-between gap-4">
|
|
<div>
|
|
<h2 class="font-semibold text-base-content">Squelette sélectionné</h2>
|
|
<p class="text-xs text-base-content/70">
|
|
{{ description }}
|
|
</p>
|
|
</div>
|
|
<span class="badge badge-outline">{{ previewBadge }}</span>
|
|
</div>
|
|
|
|
<details v-if="structure" class="collapse collapse-arrow bg-base-100">
|
|
<summary class="collapse-title text-sm font-medium">
|
|
Consulter le détail du squelette
|
|
</summary>
|
|
<div class="collapse-content text-sm text-base-content/80" :class="variant === 'component' ? 'space-y-4' : 'space-y-2'">
|
|
<!-- Custom fields: component variant (rich display) -->
|
|
<div v-if="variant === 'component' && customFields.length" class="space-y-2">
|
|
<h3 class="font-semibold text-sm text-base-content">Champs personnalisés</h3>
|
|
<ul class="space-y-2">
|
|
<li
|
|
v-for="field in customFields"
|
|
:key="field.customFieldId || field.id || field.name"
|
|
class="rounded bg-base-200/60 px-3 py-2"
|
|
>
|
|
<p class="font-medium text-sm text-base-content">
|
|
{{ field.name || field.key }}
|
|
</p>
|
|
<p class="text-xs text-base-content/70 mt-1">
|
|
Type : {{ field.type || 'text' }}<span v-if="field.required"> • Obligatoire</span>
|
|
<span v-if="Array.isArray(field.options) && field.options.length">
|
|
• Options : {{ field.options.join(', ') }}
|
|
</span>
|
|
<span v-if="field.defaultValue">
|
|
• Défaut : {{ field.defaultValue }}
|
|
</span>
|
|
</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Custom fields: piece variant (simple display) -->
|
|
<div v-if="variant === 'piece' && customFields.length" class="space-y-1">
|
|
<h3 class="font-semibold text-sm text-base-content">Champs personnalisés</h3>
|
|
<ul class="list-disc list-inside space-y-1">
|
|
<li v-for="field in customFields" :key="field.name">
|
|
<span class="font-medium">{{ field.name }}</span>
|
|
<span v-if="field.value !== undefined && field.value !== null"> : {{ field.value }}</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Pieces: component variant only -->
|
|
<div v-if="variant === 'component' && pieces.length" class="space-y-2">
|
|
<h3 class="font-semibold text-sm text-base-content">Pièces imposées</h3>
|
|
<ul class="list-disc list-inside space-y-1">
|
|
<li
|
|
v-for="(piece, index) in pieces"
|
|
:key="piece.role || piece.typePieceId || piece.familyCode || index"
|
|
>
|
|
{{ resolvePieceLabelFn(piece) }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Products: component variant only -->
|
|
<div v-if="variant === 'component' && products.length" class="space-y-2">
|
|
<h3 class="font-semibold text-sm text-base-content">Produits imposés</h3>
|
|
<ul class="list-disc list-inside space-y-1">
|
|
<li
|
|
v-for="(product, index) in products"
|
|
:key="product.role || product.typeProductId || product.familyCode || index"
|
|
>
|
|
{{ resolveProductLabelFn(product) }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Subcomponents: component variant only -->
|
|
<div v-if="variant === 'component' && subcomponents.length" class="space-y-2">
|
|
<h3 class="font-semibold text-sm text-base-content">Sous-composants</h3>
|
|
<ul class="list-disc list-inside space-y-1">
|
|
<li
|
|
v-for="(subcomponent, index) in subcomponents"
|
|
:key="subcomponent.alias || subcomponent.typeComposantId || subcomponent.familyCode || index"
|
|
>
|
|
{{ resolveSubcomponentLabelFn(subcomponent) }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Empty state: component variant -->
|
|
<p
|
|
v-if="variant === 'component' && showEmptyState && !customFields.length && !pieces.length && !products.length && !subcomponents.length"
|
|
class="text-xs text-gray-500"
|
|
>
|
|
Ce squelette ne définit pas encore de pièces, sous-composants ou valeurs par défaut.
|
|
</p>
|
|
|
|
<!-- Empty state: piece variant -->
|
|
<p v-if="variant === 'piece' && !customFields.length" class="text-xs text-base-content/70">
|
|
Ce squelette ne définit pas encore de champs personnalisés.
|
|
</p>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
getStructureCustomFields,
|
|
getStructurePieces,
|
|
getStructureProducts,
|
|
getStructureSubcomponents,
|
|
} from '~/shared/utils/structureDisplayUtils'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
structure: Record<string, any> | null
|
|
description?: string
|
|
previewBadge: string
|
|
variant: 'component' | 'piece'
|
|
showEmptyState?: boolean
|
|
resolvePieceLabel?: (piece: Record<string, any>) => string
|
|
resolveProductLabel?: (product: Record<string, any>) => string
|
|
resolveSubcomponentLabel?: (subcomponent: Record<string, any>) => string
|
|
}>(), {
|
|
description: '',
|
|
showEmptyState: false,
|
|
resolvePieceLabel: undefined,
|
|
resolveProductLabel: undefined,
|
|
resolveSubcomponentLabel: undefined,
|
|
})
|
|
|
|
const customFields = computed(() =>
|
|
getStructureCustomFields(props.structure),
|
|
)
|
|
|
|
const pieces = computed(() =>
|
|
props.variant === 'component' ? getStructurePieces(props.structure) : [],
|
|
)
|
|
|
|
const products = computed(() =>
|
|
props.variant === 'component' ? getStructureProducts(props.structure) : [],
|
|
)
|
|
|
|
const subcomponents = computed(() =>
|
|
props.variant === 'component' ? getStructureSubcomponents(props.structure) : [],
|
|
)
|
|
|
|
const fallbackLabel = (item: Record<string, any>) =>
|
|
item?.name || item?.label || item?.role || item?.alias || 'N/A'
|
|
|
|
const resolvePieceLabelFn = (piece: Record<string, any>) =>
|
|
props.resolvePieceLabel ? props.resolvePieceLabel(piece) : fallbackLabel(piece)
|
|
|
|
const resolveProductLabelFn = (product: Record<string, any>) =>
|
|
props.resolveProductLabel ? props.resolveProductLabel(product) : fallbackLabel(product)
|
|
|
|
const resolveSubcomponentLabelFn = (subcomponent: Record<string, any>) =>
|
|
props.resolveSubcomponentLabel ? props.resolveSubcomponentLabel(subcomponent) : fallbackLabel(subcomponent)
|
|
</script>
|