All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m1s
- **Nuevas tabs reorganizadas:** - Organoléptica: Selectores de familia de fragancia-aroma y sabor - Descriptiva/Afectiva: Todos los sliders de intensidad (incluye impresión global) - Defectos: Tazas no uniformes, defectuosas y tipo de defecto - Impresión Global: Vista completa con todos los componentes - **Selector de categorías mejorado:** - Permitir selección múltiple de categorías padre - Las subcategorías son la unión de las subcategorías de los padres seleccionados - Permitir selección múltiple de subcategorías - Actualizar resumen visual de selección - **Tipos actualizados:** - NotaSeleccionada ahora usa arrays para categorias y subcategorias - TabCatacion actualizado con las nuevas tabs - Funciones de actualización modificadas para trabajar con arrays - **Correcciones TypeScript:** - Usar JSON.parse(JSON.stringify()) para crear copias mutables de arrays readonly - Resolver incompatibilidades de tipos entre readonly y mutable arrays
731 lines
25 KiB
Vue
731 lines
25 KiB
Vue
<template>
|
|
<div class="formulario-muestra p-4 space-y-6">
|
|
<!-- Tab 1: Organoléptica (solo selectores de familia) -->
|
|
<div v-if="tabActiva === 'organoleptica'" class="tab-content cata-fade-in">
|
|
<h4 class="tab-section-title cata-text mb-4">
|
|
Características Organolépticas
|
|
</h4>
|
|
|
|
<!-- Selector de Familia de Fragancia/Aroma -->
|
|
<div class="form-section">
|
|
<CataSelectorFamilia
|
|
tipo="fragancia-aroma"
|
|
label="Familia de Fragancia y Aroma"
|
|
:model-value="muestra.fraganciaAromaNotas"
|
|
@update:model-value="actualizarFraganciaAroma"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Selector de Familia de Sabor -->
|
|
<div class="form-section">
|
|
<CataSelectorFamilia
|
|
tipo="sabor"
|
|
label="Familia de Sabor"
|
|
:model-value="muestra.saborNotas"
|
|
@update:model-value="actualizarSabor"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 2: Descriptiva/Afectiva (todos los sliders incluyendo impresión global) -->
|
|
<div v-if="tabActiva === 'descriptiva-afectiva'" class="tab-content cata-fade-in">
|
|
<h4 class="tab-section-title cata-text mb-4">
|
|
Intensidades Descriptivas y Afectivas
|
|
</h4>
|
|
|
|
<!-- Sliders de Fragancia -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Fragancia</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.fragancia.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.fragancia.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Aroma -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Aroma</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.aroma.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.aroma.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Sabor -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Sabor</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.sabor.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.sabor.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Sabor Residual -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Sabor Residual</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.saborResidual.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Acidez -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Acidez</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.acidez.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.acidez.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Dulzor -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Dulzor</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.dulzor.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.dulzor.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Sensación en Boca -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Sensación en la Boca</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sliders de Impresión Global -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title cata-text">Impresión Global</h5>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 3: Defectos (tazas y defectos) -->
|
|
<div v-if="tabActiva === 'defectos'" class="tab-content cata-fade-in">
|
|
<h4 class="tab-section-title cata-text mb-4">
|
|
Defectos y Uniformidad
|
|
</h4>
|
|
|
|
<!-- Tazas No Uniformes -->
|
|
<div class="form-section">
|
|
<CataSelectorTazas
|
|
tipo="uniformes"
|
|
label="Tazas NO Uniformes"
|
|
:model-value="muestra.tazasNoUniformes"
|
|
@update:model-value="actualizarTazasNoUniformes"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Tazas Defectuosas -->
|
|
<div class="form-section">
|
|
<CataSelectorTazas
|
|
tipo="defectuosas"
|
|
label="Tazas Defectuosas"
|
|
:model-value="muestra.tazasDefectuosas"
|
|
@update:model-value="actualizarTazasDefectuosas"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Tipo de Defecto -->
|
|
<div v-if="muestra.tazasDefectuosas.length > 0" class="form-section">
|
|
<label class="block text-sm font-medium mb-2 cata-text">
|
|
Tipo de Defecto
|
|
</label>
|
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
|
<button
|
|
v-for="tipo in tiposDefectos"
|
|
:key="tipo || 'ninguno'"
|
|
type="button"
|
|
:class="[
|
|
'cata-checkbox',
|
|
{ 'cata-checkbox-checked': muestra.defecto === tipo },
|
|
]"
|
|
@click="actualizarDefecto(tipo)"
|
|
>
|
|
<span class="cata-text">{{ tipo || 'Ninguno' }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab 4: Impresión Global (muestra TODOS los componentes) -->
|
|
<div v-if="tabActiva === 'impresion-global'" class="tab-content cata-fade-in">
|
|
<h4 class="tab-section-title cata-text mb-4">
|
|
Visión Global Completa
|
|
</h4>
|
|
|
|
<!-- Sección: Organoléptica -->
|
|
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
|
<h5 class="global-section-title cata-text mb-4">Características Organolépticas</h5>
|
|
|
|
<!-- Selector de Familia de Fragancia/Aroma -->
|
|
<div class="form-section mb-4">
|
|
<CataSelectorFamilia
|
|
tipo="fragancia-aroma"
|
|
label="Familia de Fragancia y Aroma"
|
|
:model-value="muestra.fraganciaAromaNotas"
|
|
@update:model-value="actualizarFraganciaAroma"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Selector de Familia de Sabor -->
|
|
<div class="form-section">
|
|
<CataSelectorFamilia
|
|
tipo="sabor"
|
|
label="Familia de Sabor"
|
|
:model-value="muestra.saborNotas"
|
|
@update:model-value="actualizarSabor"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección: Intensidades -->
|
|
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
|
<h5 class="global-section-title cata-text mb-4">Intensidades Descriptivas y Afectivas</h5>
|
|
|
|
<!-- Fragancia -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Fragancia</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.fragancia.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.fragancia.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Aroma -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Aroma</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.aroma.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.aroma.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sabor -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Sabor</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.sabor.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.sabor.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sabor Residual -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Sabor Residual</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.saborResidual.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Acidez -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Acidez</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.acidez.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.acidez.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dulzor -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Dulzor</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.dulzor.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.dulzor.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sensación en Boca -->
|
|
<div class="form-section mb-4">
|
|
<h6 class="form-subsection-title cata-text">Sensación en la Boca</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Impresión Global -->
|
|
<div class="form-section">
|
|
<h6 class="form-subsection-title cata-text">Impresión Global</h6>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<CataSliderIntensidad
|
|
tipo="descriptiva"
|
|
label="Descriptiva"
|
|
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
|
/>
|
|
<CataSliderIntensidad
|
|
tipo="afectiva"
|
|
label="Afectiva"
|
|
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección: Defectos -->
|
|
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
|
<h5 class="global-section-title cata-text mb-4">Defectos y Uniformidad</h5>
|
|
|
|
<!-- Tazas No Uniformes -->
|
|
<div class="form-section mb-4">
|
|
<CataSelectorTazas
|
|
tipo="uniformes"
|
|
label="Tazas NO Uniformes"
|
|
:model-value="muestra.tazasNoUniformes"
|
|
@update:model-value="actualizarTazasNoUniformes"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Tazas Defectuosas -->
|
|
<div class="form-section mb-4">
|
|
<CataSelectorTazas
|
|
tipo="defectuosas"
|
|
label="Tazas Defectuosas"
|
|
:model-value="muestra.tazasDefectuosas"
|
|
@update:model-value="actualizarTazasDefectuosas"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Tipo de Defecto -->
|
|
<div v-if="muestra.tazasDefectuosas.length > 0" class="form-section">
|
|
<label class="block text-sm font-medium mb-2 cata-text">
|
|
Tipo de Defecto
|
|
</label>
|
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
|
<button
|
|
v-for="tipo in tiposDefectos"
|
|
:key="tipo || 'ninguno'"
|
|
type="button"
|
|
:class="[
|
|
'cata-checkbox',
|
|
{ 'cata-checkbox-checked': muestra.defecto === tipo },
|
|
]"
|
|
@click="actualizarDefecto(tipo)"
|
|
>
|
|
<span class="cata-text">{{ tipo || 'Ninguno' }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección: Detalles Adicionales -->
|
|
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
|
<h5 class="global-section-title cata-text mb-4">Detalles Adicionales</h5>
|
|
|
|
<!-- Sensaciones en Boca (selección múltiple) -->
|
|
<div class="form-section mb-4">
|
|
<label class="block text-sm font-medium mb-2 cata-text">
|
|
Sensaciones en la Boca (múltiples)
|
|
</label>
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
|
<button
|
|
v-for="sensacion in sensacionesBoca"
|
|
:key="sensacion"
|
|
type="button"
|
|
:class="[
|
|
'cata-checkbox',
|
|
{ 'cata-checkbox-checked': muestra.sensacionEnBoca.includes(sensacion) },
|
|
]"
|
|
@click="toggleSensacionBoca(sensacion)"
|
|
>
|
|
<span class="cata-text text-sm">{{ sensacion }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Gustos Predominantes (máx 2) -->
|
|
<div class="form-section mb-4">
|
|
<label class="block text-sm font-medium mb-2 cata-text">
|
|
Gustos Predominantes (mín 1, máx 2)
|
|
</label>
|
|
<div class="grid grid-cols-2 sm:grid-cols-5 gap-2">
|
|
<button
|
|
v-for="gusto in gustosPredominantes"
|
|
:key="gusto"
|
|
type="button"
|
|
:class="[
|
|
'cata-checkbox',
|
|
{ 'cata-checkbox-checked': muestra.gustosPredominantes.includes(gusto) },
|
|
]"
|
|
:disabled="!muestra.gustosPredominantes.includes(gusto) && muestra.gustosPredominantes.length >= 2"
|
|
@click="toggleGustoPredominante(gusto)"
|
|
>
|
|
<span class="cata-text">{{ gusto }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Otras Notas -->
|
|
<div class="form-section">
|
|
<label class="block text-sm font-medium mb-2 cata-text">
|
|
Otras Notas
|
|
</label>
|
|
<textarea
|
|
v-model="otrasNotasLocal"
|
|
class="cata-input w-full min-h-[100px] resize-y"
|
|
placeholder="Notas adicionales sobre el café, cuerpo, balance, etc..."
|
|
@blur="actualizarOtrasNotas"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Puntaje Final (solo lectura) -->
|
|
<div class="global-section p-4 cata-outline-box rounded-lg">
|
|
<div class="puntaje-final">
|
|
<div class="flex items-baseline justify-between">
|
|
<span class="text-sm cata-text opacity-75">Puntaje Final:</span>
|
|
<span class="text-3xl font-bold cata-text">{{ muestra.puntajeFinal }}</span>
|
|
</div>
|
|
<p class="text-xs cata-text opacity-60 mt-1">
|
|
Suma de valores afectivos
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { Muestra, NotaSeleccionada, TipoDefecto, SensacionBoca, GustoPredominante } from '~/types/catacion'
|
|
import type { TabCatacion } from '~/composables/useCatacion'
|
|
import { SENSACIONES_BOCA, GUSTOS_PREDOMINANTES, TIPOS_DEFECTOS } from '~/types/catacion'
|
|
|
|
interface FormularioMuestraProps {
|
|
/** Muestra a editar */
|
|
muestra: Muestra
|
|
/** Tab activa */
|
|
tabActiva: TabCatacion
|
|
}
|
|
|
|
const props = defineProps<FormularioMuestraProps>()
|
|
|
|
const { actualizarIntensidad: actualizarIntensidadCatacion } = useCatacion()
|
|
|
|
// Listas para los selectores
|
|
const sensacionesBoca = SENSACIONES_BOCA
|
|
const gustosPredominantes = GUSTOS_PREDOMINANTES
|
|
const tiposDefectos = TIPOS_DEFECTOS
|
|
|
|
// Estado local para otras notas
|
|
const otrasNotasLocal = ref(props.muestra.otrasNotas)
|
|
|
|
// Actualizar intensidad
|
|
const actualizarIntensidad = async (
|
|
parametro: keyof Muestra['intensidades'],
|
|
tipo: 'descriptiva' | 'afectiva',
|
|
valor: number | null
|
|
) => {
|
|
await actualizarIntensidadCatacion(props.muestra.muestraId, parametro, tipo, valor)
|
|
}
|
|
|
|
// Actualizar fragancia/aroma
|
|
const { actualizarFraganciaAroma: actualizarFraganciaAromaCatacion } = useCatacion()
|
|
const actualizarFraganciaAroma = async (nota: NotaSeleccionada) => {
|
|
await actualizarFraganciaAromaCatacion(
|
|
props.muestra.muestraId,
|
|
nota.categorias,
|
|
nota.subcategorias,
|
|
nota.notaEspecifica
|
|
)
|
|
}
|
|
|
|
// Actualizar sabor
|
|
const { actualizarSabor: actualizarSaborCatacion } = useCatacion()
|
|
const actualizarSabor = async (nota: NotaSeleccionada) => {
|
|
await actualizarSaborCatacion(
|
|
props.muestra.muestraId,
|
|
nota.categorias,
|
|
nota.subcategorias,
|
|
nota.notaEspecifica
|
|
)
|
|
}
|
|
|
|
// Actualizar tazas
|
|
const { actualizarTazasNoUniformes: actualizarTazasNoUniformesCatacion, actualizarTazasDefectuosas: actualizarTazasDefectuosasCatacion } = useCatacion()
|
|
const actualizarTazasNoUniformes = async (tazas: number[]) => {
|
|
await actualizarTazasNoUniformesCatacion(props.muestra.muestraId, tazas)
|
|
}
|
|
|
|
const actualizarTazasDefectuosas = async (tazas: number[]) => {
|
|
await actualizarTazasDefectuosasCatacion(props.muestra.muestraId, tazas)
|
|
}
|
|
|
|
// Actualizar defecto
|
|
const { actualizarDefecto: actualizarDefectoCatacion } = useCatacion()
|
|
const actualizarDefecto = async (defecto: TipoDefecto) => {
|
|
await actualizarDefectoCatacion(props.muestra.muestraId, defecto)
|
|
}
|
|
|
|
// Toggle sensación en boca
|
|
const { actualizarSensacionBoca } = useCatacion()
|
|
const toggleSensacionBoca = async (sensacion: SensacionBoca) => {
|
|
const sensaciones = [...props.muestra.sensacionEnBoca]
|
|
const index = sensaciones.indexOf(sensacion)
|
|
|
|
if (index > -1) {
|
|
sensaciones.splice(index, 1)
|
|
} else {
|
|
sensaciones.push(sensacion)
|
|
}
|
|
|
|
await actualizarSensacionBoca(props.muestra.muestraId, sensaciones)
|
|
}
|
|
|
|
// Toggle gusto predominante
|
|
const { actualizarGustosPredominantes } = useCatacion()
|
|
const toggleGustoPredominante = async (gusto: GustoPredominante) => {
|
|
const gustos = [...props.muestra.gustosPredominantes]
|
|
const index = gustos.indexOf(gusto)
|
|
|
|
if (index > -1) {
|
|
gustos.splice(index, 1)
|
|
} else {
|
|
if (gustos.length >= 2) return // Máximo 2
|
|
gustos.push(gusto)
|
|
}
|
|
|
|
if (gustos.length === 0) return // Mínimo 1
|
|
|
|
await actualizarGustosPredominantes(props.muestra.muestraId, gustos)
|
|
}
|
|
|
|
// Actualizar otras notas
|
|
const { actualizarOtrasNotas: actualizarOtrasNotasCatacion } = useCatacion()
|
|
const actualizarOtrasNotas = async () => {
|
|
const notas = otrasNotasLocal.value.trim()
|
|
await actualizarOtrasNotasCatacion(props.muestra.muestraId, notas)
|
|
}
|
|
|
|
// Sincronizar otras notas cuando cambia la muestra
|
|
watch(() => props.muestra.otrasNotas, (newVal) => {
|
|
if (newVal !== otrasNotasLocal.value) {
|
|
otrasNotasLocal.value = newVal
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.formulario-muestra {
|
|
width: 100%;
|
|
}
|
|
|
|
.tab-section-title {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
border-bottom: 1px solid;
|
|
padding-bottom: 0.5rem;
|
|
border-color: color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
|
}
|
|
|
|
.global-section-title {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.form-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.form-section-title {
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
.form-subsection-title {
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
opacity: 0.7;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.puntaje-final {
|
|
text-align: center;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 768px) {
|
|
.formulario-muestra {
|
|
padding: 0.75rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.tab-section-title {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.global-section-title {
|
|
font-size: 0.9rem;
|
|
}
|
|
}
|
|
</style>
|