146 lines
4.2 KiB
Vue
146 lines
4.2 KiB
Vue
<template>
|
|
<v-dialog
|
|
max-width="560"
|
|
:model-value="visible"
|
|
@update:model-value="onUpdateVisible"
|
|
>
|
|
<v-card v-if="relation || product">
|
|
<v-card-title class="d-flex align-center">
|
|
<v-icon class="mr-2" color="teal" icon="mdi-package-variant" />
|
|
<span class="font-weight-bold">{{ productName }}</span>
|
|
</v-card-title>
|
|
<v-divider />
|
|
<v-card-text>
|
|
<img
|
|
v-if="productImage"
|
|
alt="Imagen del producto"
|
|
class="provenance-image rounded-lg border mb-3"
|
|
:src="productImage"
|
|
>
|
|
<div
|
|
v-if="!hasLocation"
|
|
class="d-flex align-start mb-3"
|
|
>
|
|
<v-icon class="mr-3" color="grey" icon="mdi-map-marker-off" />
|
|
<div>
|
|
<div class="text-subtitle-2 font-weight-bold">
|
|
Geolocalización
|
|
</div>
|
|
<div class="text-body-1">
|
|
{{ locationNote }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-for="row in rows"
|
|
:key="row.kind"
|
|
class="d-flex align-start mb-3"
|
|
>
|
|
<v-icon class="mr-3" :color="row.color" :icon="row.icon" />
|
|
<div>
|
|
<div class="text-subtitle-2 font-weight-bold">
|
|
{{ row.label }}
|
|
</div>
|
|
<div class="text-body-1">
|
|
{{ row.name }}
|
|
</div>
|
|
<div
|
|
v-for="detail in row.details"
|
|
:key="detail.label"
|
|
class="text-body-2 text-medium-emphasis"
|
|
>
|
|
{{ detail.label }}: {{ detail.value }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn variant="text" @click="close">Cerrar</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
|
|
const props = defineProps({
|
|
visible: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
relation: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
product: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
})
|
|
|
|
const emit = defineEmits(['update:visible'])
|
|
|
|
const ENTITY_INFO = {
|
|
supplier: { label: 'Proveedor', icon: 'mdi-truck', color: 'blue' },
|
|
organization: { label: 'Organización', icon: 'mdi-domain', color: 'orange' },
|
|
municipality: { label: 'Municipio', icon: 'mdi-map-marker', color: 'green' },
|
|
department: { label: 'Departamento', icon: 'mdi-map', color: 'indigo' },
|
|
country: { label: 'País', icon: 'mdi-earth', color: 'purple' },
|
|
}
|
|
|
|
const productName = computed(() => props.product?.name || 'Producto')
|
|
const productImage = computed(() => props.product?.catalogue_images?.[0] || null)
|
|
const hasLocation = computed(() => !!(props.relation?.municipality || props.relation?.department))
|
|
const locationNote = computed(() => {
|
|
if (props.relation) return 'Aún sin geolocalización registrada.'
|
|
return 'Aún no se ha vinculado un proveedor a este producto.'
|
|
})
|
|
|
|
function entityDetails (kind, entity) {
|
|
const details = []
|
|
if (kind === 'supplier' || kind === 'organization') {
|
|
if (entity.description) details.push({ label: 'Descripción', value: entity.description })
|
|
if (entity.website) details.push({ label: 'Sitio web', value: entity.website })
|
|
if (entity.contact_email) details.push({ label: 'Correo', value: entity.contact_email })
|
|
if (entity.contact_phone) details.push({ label: 'Teléfono', value: entity.contact_phone })
|
|
}
|
|
return details
|
|
}
|
|
|
|
const rows = computed(() => {
|
|
const rel = props.relation || {}
|
|
return ['supplier', 'organization', 'municipality', 'department', 'country']
|
|
.filter(kind => rel[kind])
|
|
.map(kind => {
|
|
const info = ENTITY_INFO[kind]
|
|
return {
|
|
kind,
|
|
label: info.label,
|
|
icon: info.icon,
|
|
color: info.color,
|
|
name: rel[kind].name,
|
|
details: entityDetails(kind, rel[kind]),
|
|
}
|
|
})
|
|
})
|
|
|
|
function onUpdateVisible (value) {
|
|
emit('update:visible', value)
|
|
}
|
|
|
|
function close () {
|
|
emit('update:visible', false)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.provenance-image {
|
|
display: block;
|
|
max-height: 220px;
|
|
max-width: 100%;
|
|
object-fit: contain;
|
|
}
|
|
</style>
|