Files
Inventory/app/components/StructureSubComponentEditor.vue
2025-09-29 15:05:54 +02:00

130 lines
3.2 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="border border-base-200 rounded-lg bg-base-100" :class="depthPadding">
<div class="flex items-center justify-between gap-3 px-4 py-3">
<div class="flex-1">
<select
v-model="node.typeComposantId"
class="select select-bordered select-sm w-full"
@change="handleComponentTypeSelect(node)"
>
<option value="">
Sélectionner une famille de composant
</option>
<option
v-for="type in componentTypes"
:key="type.id"
:value="type.id"
>
{{ formatComponentTypeOption(type) }}
</option>
</select>
<p class="mt-1 text-[11px] text-gray-500">
{{ node.typeComposantId ? `Sélection : ${getComponentTypeLabel(node.typeComposantId) || 'Inconnue'}` : 'Aucune famille sélectionnée' }}
</p>
</div>
<button type="button" class="btn btn-error btn-xs btn-square" @click="emit('remove')">
<IconLucideTrash class="w-4 h-4" aria-hidden="true" />
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
import IconLucideTrash from '~icons/lucide/trash'
defineOptions({ name: 'StructureSubComponentEditor' })
type ModelTypeOption = {
id: string
name: string
code?: string | null
}
const props = withDefaults(defineProps<{
node: Record<string, any>
depth?: number
componentTypes?: ModelTypeOption[]
}>(), {
depth: 0,
componentTypes: () => [],
})
const emit = defineEmits(['remove'])
const componentTypes = computed(() => props.componentTypes ?? [])
const depthPadding = computed(() => {
const level = props.depth ?? 0
return level > 0 ? `ml-${Math.min(level * 4, 12)}` : ''
})
const formatModelTypeOption = (type: ModelTypeOption | undefined | null) => {
if (!type) {
return ''
}
return type.code ? `${type.name} (${type.code})` : type.name
}
const formatComponentTypeOption = (type: ModelTypeOption | undefined | null) =>
formatModelTypeOption(type)
const componentTypeMap = computed(() => {
const map = new Map<string, ModelTypeOption>()
componentTypes.value.forEach((type) => {
if (type && typeof type.id === 'string') {
map.set(type.id, type)
}
})
return map
})
const getComponentTypeLabel = (id?: string) => {
if (!id) return ''
return formatModelTypeOption(componentTypeMap.value.get(id))
}
const syncComponentType = (component: any) => {
if (!component) {
return
}
const id = typeof component.typeComposantId === 'string'
? component.typeComposantId
: ''
if (!id) {
component.typeComposantLabel = ''
component.name = ''
return
}
const option = componentTypeMap.value.get(id)
if (!option) {
component.typeComposantLabel = ''
component.name = ''
return
}
component.typeComposantLabel = formatModelTypeOption(option)
component.name = option.name || component.typeComposantLabel
}
const handleComponentTypeSelect = (component: any) => {
syncComponentType(component)
}
watch(componentTypes, () => {
syncComponentType(props.node)
}, { deep: true, immediate: true })
watch(
() => props.node.typeComposantId,
() => {
syncComponentType(props.node)
}
)
</script>
<style scoped>
</style>