Fix: Eliminar componentes duplicados que causaban conflicto en el build
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m4s
- Eliminar CataResumenMuestra.vue y CataFormularioMuestra.vue duplicados - Usar componentes existentes en components/cata/ que ya se auto-registran como CataResumenMuestra y CataFormularioMuestra - Resolver conflicto de nombres en Nuxt que impedía el build
This commit is contained in:
@@ -161,5 +161,48 @@ export default defineAppConfig({
|
|||||||
root: 'bg-transparent border border-primary/50 dark:border-primary focus:ring-2 focus:ring-primary dark:font-mono',
|
root: 'bg-transparent border border-primary/50 dark:border-primary focus:ring-2 focus:ring-primary dark:font-mono',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Notifications (Toast): Estilo outline con los colores de la app
|
||||||
|
notification: {
|
||||||
|
slots: {
|
||||||
|
root: 'bg-transparent border-2 border-primary/50 dark:border-primary backdrop-blur-sm',
|
||||||
|
wrapper: 'w-full',
|
||||||
|
title: 'text-foreground font-semibold dark:font-mono dark:text-shadow',
|
||||||
|
description: 'text-foreground/80 dark:font-mono dark:font-light',
|
||||||
|
icon: 'shrink-0',
|
||||||
|
avatar: 'shrink-0',
|
||||||
|
actions: 'flex gap-1.5 shrink-0',
|
||||||
|
close: 'shrink-0',
|
||||||
|
progress: 'absolute inset-x-0 bottom-0 h-1 z-10',
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
color: {
|
||||||
|
primary: {
|
||||||
|
root: 'dark:shadow-[0_0_12px_rgba(0,255,0,0.3)]',
|
||||||
|
progress: 'bg-primary',
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
root: 'border-green-500/50 dark:border-green-500 dark:shadow-[0_0_12px_rgba(0,255,0,0.3)]',
|
||||||
|
progress: 'bg-green-500',
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
root: 'border-red-500/50 dark:border-red-500 dark:shadow-[0_0_12px_rgba(255,0,0,0.3)]',
|
||||||
|
progress: 'bg-red-500',
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
root: 'border-yellow-500/50 dark:border-yellow-500 dark:shadow-[0_0_12px_rgba(255,255,0,0.3)]',
|
||||||
|
progress: 'bg-yellow-500',
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
root: 'border-blue-500/50 dark:border-blue-500 dark:shadow-[0_0_12px_rgba(0,150,255,0.3)]',
|
||||||
|
progress: 'bg-blue-500',
|
||||||
|
},
|
||||||
|
neutral: {
|
||||||
|
root: 'dark:shadow-[0_0_12px_rgba(100,100,100,0.3)]',
|
||||||
|
progress: 'bg-gray-500',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,447 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="formulario-muestra cata-text p-4">
|
|
||||||
<!-- Tab: Fragancia/Aroma -->
|
|
||||||
<div v-if="tabActiva === 'fragancia-aroma'" class="tab-content">
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<!-- Fragancia -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Fragancia</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="fraganciaDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarFragancia"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="fraganciaAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarFragancia"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Aroma -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Aroma</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="aromaDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarAroma"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="aromaAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarAroma"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Notas de Fragancia/Aroma -->
|
|
||||||
<div class="mt-6">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Notas de Fragancia/Aroma</label>
|
|
||||||
<div class="text-xs opacity-60 mb-2">Puedes escribir tus notas libremente</div>
|
|
||||||
<textarea
|
|
||||||
v-model="notasFraganciaAroma"
|
|
||||||
rows="3"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="Describe las notas de fragancia y aroma..."
|
|
||||||
@blur="actualizarNotasFragancia"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tab: Sabor -->
|
|
||||||
<div v-else-if="tabActiva === 'sabor'" class="tab-content">
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<!-- Sabor -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Sabor</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="saborDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarSabor"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="saborAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarSabor"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sabor Residual -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Sabor Residual</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="saborResidualDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarSaborResidual"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="saborResidualAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarSaborResidual"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Acidez -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Acidez</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="acidezDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarAcidez"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="acidezAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarAcidez"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Dulzor -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Dulzor</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="dulzorDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarDulzor"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="dulzorAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarDulzor"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Notas de Sabor -->
|
|
||||||
<div class="mt-6">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Notas de Sabor</label>
|
|
||||||
<div class="text-xs opacity-60 mb-2">Puedes escribir tus notas libremente</div>
|
|
||||||
<textarea
|
|
||||||
v-model="notasSabor"
|
|
||||||
rows="3"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="Describe las notas de sabor..."
|
|
||||||
@blur="actualizarNotasSabor"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tab: Impresión Global -->
|
|
||||||
<div v-else-if="tabActiva === 'impresion-global'" class="tab-content">
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<!-- Sensación en Boca -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Sensación en Boca</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="sensacionBocaDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarSensacionBoca"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="sensacionBocaAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarSensacionBoca"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Impresión Global -->
|
|
||||||
<div class="campo-grupo">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Impresión Global</label>
|
|
||||||
<div class="flex gap-3 items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Descriptiva (1-10)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="impresionGlobalDescriptiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="10"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-10"
|
|
||||||
@change="actualizarImpresionGlobal"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="text-xs opacity-75 mb-1 block">Afectiva (1-15)</label>
|
|
||||||
<input
|
|
||||||
v-model.number="impresionGlobalAfectiva"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="15"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="1-15"
|
|
||||||
@change="actualizarImpresionGlobal"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Notas Adicionales -->
|
|
||||||
<div class="mt-6">
|
|
||||||
<label class="text-sm font-semibold mb-3 block cata-text">Notas Adicionales</label>
|
|
||||||
<div class="text-xs opacity-60 mb-2">Observaciones generales sobre la muestra</div>
|
|
||||||
<textarea
|
|
||||||
v-model="otrasNotas"
|
|
||||||
rows="4"
|
|
||||||
class="cata-input w-full"
|
|
||||||
placeholder="Escribe tus observaciones generales..."
|
|
||||||
@blur="actualizarOtrasNotas"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { Muestra } from '~/types/catacion'
|
|
||||||
import type { TabCatacion } from '~/composables/useCatacion'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
muestra: Muestra
|
|
||||||
tabActiva: TabCatacion
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const { actualizarIntensidad, actualizarFraganciaAroma, actualizarSabor, actualizarOtrasNotas: actualizarOtrasNotasComposable } = useCatacion()
|
|
||||||
|
|
||||||
// Valores reactivos para Fragancia
|
|
||||||
const fraganciaDescriptiva = ref(props.muestra.intensidades.fragancia.descriptiva)
|
|
||||||
const fraganciaAfectiva = ref(props.muestra.intensidades.fragancia.afectiva)
|
|
||||||
const aromaDescriptiva = ref(props.muestra.intensidades.aroma.descriptiva)
|
|
||||||
const aromaAfectiva = ref(props.muestra.intensidades.aroma.afectiva)
|
|
||||||
|
|
||||||
// Valores reactivos para Sabor
|
|
||||||
const saborDescriptiva = ref(props.muestra.intensidades.sabor.descriptiva)
|
|
||||||
const saborAfectiva = ref(props.muestra.intensidades.sabor.afectiva)
|
|
||||||
const saborResidualDescriptiva = ref(props.muestra.intensidades.saborResidual.descriptiva)
|
|
||||||
const saborResidualAfectiva = ref(props.muestra.intensidades.saborResidual.afectiva)
|
|
||||||
const acidezDescriptiva = ref(props.muestra.intensidades.acidez.descriptiva)
|
|
||||||
const acidezAfectiva = ref(props.muestra.intensidades.acidez.afectiva)
|
|
||||||
const dulzorDescriptiva = ref(props.muestra.intensidades.dulzor.descriptiva)
|
|
||||||
const dulzorAfectiva = ref(props.muestra.intensidades.dulzor.afectiva)
|
|
||||||
|
|
||||||
// Valores reactivos para Impresión Global
|
|
||||||
const sensacionBocaDescriptiva = ref(props.muestra.intensidades.sensacionBoca.descriptiva)
|
|
||||||
const sensacionBocaAfectiva = ref(props.muestra.intensidades.sensacionBoca.afectiva)
|
|
||||||
const impresionGlobalDescriptiva = ref(props.muestra.intensidades.impresionGlobal.descriptiva)
|
|
||||||
const impresionGlobalAfectiva = ref(props.muestra.intensidades.impresionGlobal.afectiva)
|
|
||||||
|
|
||||||
// Notas de texto
|
|
||||||
const notasFraganciaAroma = ref(props.muestra.fraganciaAromaNotas.notaEspecifica || '')
|
|
||||||
const notasSabor = ref(props.muestra.saborNotas.notaEspecifica || '')
|
|
||||||
const otrasNotas = ref(props.muestra.otrasNotas)
|
|
||||||
|
|
||||||
// Actualizar cuando cambie la prop
|
|
||||||
watch(() => props.muestra, (nuevaMuestra) => {
|
|
||||||
fraganciaDescriptiva.value = nuevaMuestra.intensidades.fragancia.descriptiva
|
|
||||||
fraganciaAfectiva.value = nuevaMuestra.intensidades.fragancia.afectiva
|
|
||||||
aromaDescriptiva.value = nuevaMuestra.intensidades.aroma.descriptiva
|
|
||||||
aromaAfectiva.value = nuevaMuestra.intensidades.aroma.afectiva
|
|
||||||
|
|
||||||
saborDescriptiva.value = nuevaMuestra.intensidades.sabor.descriptiva
|
|
||||||
saborAfectiva.value = nuevaMuestra.intensidades.sabor.afectiva
|
|
||||||
saborResidualDescriptiva.value = nuevaMuestra.intensidades.saborResidual.descriptiva
|
|
||||||
saborResidualAfectiva.value = nuevaMuestra.intensidades.saborResidual.afectiva
|
|
||||||
acidezDescriptiva.value = nuevaMuestra.intensidades.acidez.descriptiva
|
|
||||||
acidezAfectiva.value = nuevaMuestra.intensidades.acidez.afectiva
|
|
||||||
dulzorDescriptiva.value = nuevaMuestra.intensidades.dulzor.descriptiva
|
|
||||||
dulzorAfectiva.value = nuevaMuestra.intensidades.dulzor.afectiva
|
|
||||||
|
|
||||||
sensacionBocaDescriptiva.value = nuevaMuestra.intensidades.sensacionBoca.descriptiva
|
|
||||||
sensacionBocaAfectiva.value = nuevaMuestra.intensidades.sensacionBoca.afectiva
|
|
||||||
impresionGlobalDescriptiva.value = nuevaMuestra.intensidades.impresionGlobal.descriptiva
|
|
||||||
impresionGlobalAfectiva.value = nuevaMuestra.intensidades.impresionGlobal.afectiva
|
|
||||||
|
|
||||||
notasFraganciaAroma.value = nuevaMuestra.fraganciaAromaNotas.notaEspecifica || ''
|
|
||||||
notasSabor.value = nuevaMuestra.saborNotas.notaEspecifica || ''
|
|
||||||
otrasNotas.value = nuevaMuestra.otrasNotas
|
|
||||||
}, { deep: true })
|
|
||||||
|
|
||||||
// Métodos de actualización
|
|
||||||
const actualizarFragancia = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'fragancia', 'descriptiva', fraganciaDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'fragancia', 'afectiva', fraganciaAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarAroma = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'aroma', 'descriptiva', aromaDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'aroma', 'afectiva', aromaAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarSabor = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'sabor', 'descriptiva', saborDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'sabor', 'afectiva', saborAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarSaborResidual = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'saborResidual', 'descriptiva', saborResidualDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'saborResidual', 'afectiva', saborResidualAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarAcidez = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'acidez', 'descriptiva', acidezDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'acidez', 'afectiva', acidezAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarDulzor = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'dulzor', 'descriptiva', dulzorDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'dulzor', 'afectiva', dulzorAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarSensacionBoca = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'sensacionBoca', 'descriptiva', sensacionBocaDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'sensacionBoca', 'afectiva', sensacionBocaAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarImpresionGlobal = async () => {
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'impresionGlobal', 'descriptiva', impresionGlobalDescriptiva.value)
|
|
||||||
await actualizarIntensidad(props.muestra.muestraId, 'impresionGlobal', 'afectiva', impresionGlobalAfectiva.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarNotasFragancia = async () => {
|
|
||||||
await actualizarFraganciaAroma(props.muestra.muestraId, null, null, notasFraganciaAroma.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarNotasSabor = async () => {
|
|
||||||
await actualizarSabor(props.muestra.muestraId, null, null, notasSabor.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actualizarOtrasNotas = async () => {
|
|
||||||
await actualizarOtrasNotasComposable(props.muestra.muestraId, otrasNotas.value)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.campo-grupo {
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
border: 1px solid color-mix(in srgb, var(--cata-primary) 20%, transparent);
|
|
||||||
background: color-mix(in srgb, var(--cata-primary) 5%, transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-content {
|
|
||||||
animation: fadeIn 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="resumen-muestra flex items-center justify-between gap-4 w-full">
|
|
||||||
<!-- Información básica -->
|
|
||||||
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
||||||
<div class="muestra-numero cata-text font-bold text-lg">
|
|
||||||
#{{ muestra.muestraId }}
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 min-w-0">
|
|
||||||
<div class="muestra-nombre cata-text font-semibold truncate">
|
|
||||||
{{ muestra.nombre }}
|
|
||||||
</div>
|
|
||||||
<div class="muestra-stats text-xs cata-text opacity-60 flex items-center gap-2">
|
|
||||||
<span>Puntaje {{ muestra.puntajeFinal }}</span>
|
|
||||||
<span class="opacity-40">•</span>
|
|
||||||
<span>{{ porcentajeCompletitud }}% completado</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Indicadores de completitud -->
|
|
||||||
<div class="muestra-indicadores flex items-center gap-2 text-xs">
|
|
||||||
<!-- Fragancia/Aroma -->
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
'indicador-badge px-2 py-1 rounded',
|
|
||||||
tieneFraganciaAroma ? 'bg-success/20 text-success' : 'bg-muted/20 text-muted',
|
|
||||||
]"
|
|
||||||
title="Fragancia/Aroma"
|
|
||||||
>
|
|
||||||
<span class="hidden sm:inline">F:</span>
|
|
||||||
{{ intensidadesFormatted.fragancia }}/{{ intensidadesFormatted.aroma }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sabor -->
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
'indicador-badge px-2 py-1 rounded',
|
|
||||||
tieneSabor ? 'bg-success/20 text-success' : 'bg-muted/20 text-muted',
|
|
||||||
]"
|
|
||||||
title="Sabor"
|
|
||||||
>
|
|
||||||
<span class="hidden sm:inline">S:</span>
|
|
||||||
{{ intensidadesFormatted.sabor }}/{{ intensidadesFormatted.saborResidual }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Acidez -->
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
'indicador-badge px-2 py-1 rounded',
|
|
||||||
tieneAcidez ? 'bg-success/20 text-success' : 'bg-muted/20 text-muted',
|
|
||||||
]"
|
|
||||||
title="Acidez"
|
|
||||||
>
|
|
||||||
<span class="hidden sm:inline">Ac:</span>
|
|
||||||
{{ intensidadesFormatted.acidez }}/{{ intensidadesFormatted.dulzor }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Barra de progreso -->
|
|
||||||
<div class="progreso-container hidden md:block w-24">
|
|
||||||
<div class="progreso-bg h-2 rounded-full bg-muted/20 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="progreso-fill h-full bg-primary transition-all"
|
|
||||||
:style="{ width: `${porcentajeCompletitud}%` }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { Muestra } from '~/types/catacion'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
muestra: Muestra
|
|
||||||
porcentajeCompletitud: number
|
|
||||||
}>()
|
|
||||||
|
|
||||||
// Formatear intensidades para mostrar
|
|
||||||
const intensidadesFormatted = computed(() => ({
|
|
||||||
fragancia: props.muestra.intensidades.fragancia.afectiva ?? '-',
|
|
||||||
aroma: props.muestra.intensidades.aroma.afectiva ?? '-',
|
|
||||||
sabor: props.muestra.intensidades.sabor.afectiva ?? '-',
|
|
||||||
saborResidual: props.muestra.intensidades.saborResidual.afectiva ?? '-',
|
|
||||||
acidez: props.muestra.intensidades.acidez.afectiva ?? '-',
|
|
||||||
dulzor: props.muestra.intensidades.dulzor.afectiva ?? '-',
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Verificar si las secciones están completas
|
|
||||||
const tieneFraganciaAroma = computed(() =>
|
|
||||||
props.muestra.intensidades.fragancia.afectiva !== null &&
|
|
||||||
props.muestra.intensidades.aroma.afectiva !== null
|
|
||||||
)
|
|
||||||
|
|
||||||
const tieneSabor = computed(() =>
|
|
||||||
props.muestra.intensidades.sabor.afectiva !== null &&
|
|
||||||
props.muestra.intensidades.saborResidual.afectiva !== null
|
|
||||||
)
|
|
||||||
|
|
||||||
const tieneAcidez = computed(() =>
|
|
||||||
props.muestra.intensidades.acidez.afectiva !== null &&
|
|
||||||
props.muestra.intensidades.dulzor.afectiva !== null
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.resumen-muestra {
|
|
||||||
min-height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.muestra-numero {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicador-badge {
|
|
||||||
font-weight: 600;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.muestra-indicadores {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicador-badge {
|
|
||||||
font-size: 0.625rem;
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -2,12 +2,16 @@
|
|||||||
<div v-if="user" class="cata-user-info">
|
<div v-if="user" class="cata-user-info">
|
||||||
<div class="cata-outline-box rounded-lg p-4">
|
<div class="cata-outline-box rounded-lg p-4">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<!-- Avatar simple con inicial -->
|
<!-- Avatar clickeable para verificar sesión -->
|
||||||
<div class="user-avatar cata-outline-box">
|
<button
|
||||||
|
class="user-avatar cata-outline-box cursor-pointer transition-all hover:scale-105 active:scale-95"
|
||||||
|
@click="handleCheckSession"
|
||||||
|
title="Verificar estado de sesión"
|
||||||
|
>
|
||||||
<span class="cata-text text-xl font-semibold">
|
<span class="cata-text text-xl font-semibold">
|
||||||
{{ userInitial }}
|
{{ userInitial }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<!-- Info del usuario -->
|
<!-- Info del usuario -->
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
@@ -19,21 +23,46 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Botón de logout compacto -->
|
<!-- Botones de acción -->
|
||||||
<button
|
<div class="flex items-center gap-2">
|
||||||
class="cata-button p-2 flex-shrink-0"
|
<!-- Botón de cambio de tema -->
|
||||||
@click="handleLogout"
|
<button
|
||||||
title="Cerrar sesión"
|
class="cata-button p-2 flex items-center justify-center flex-shrink-0"
|
||||||
>
|
@click="toggleTheme"
|
||||||
<UIcon name="i-lucide-log-out" class="w-4 h-4" />
|
:title="isDark ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro'"
|
||||||
</button>
|
>
|
||||||
|
<UIcon :name="isDark ? 'i-lucide-sun' : 'i-lucide-moon'" class="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Botón de home -->
|
||||||
|
<button
|
||||||
|
class="cata-button p-2 flex items-center justify-center flex-shrink-0"
|
||||||
|
@click="goToHome"
|
||||||
|
title="Ir al inicio del ecosistema Nucleo"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-home" class="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Botón de logout -->
|
||||||
|
<button
|
||||||
|
class="cata-button p-2 flex items-center justify-center flex-shrink-0"
|
||||||
|
@click="handleLogout"
|
||||||
|
title="Cerrar sesión"
|
||||||
|
>
|
||||||
|
<UIcon name="i-lucide-log-out" class="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { user } = useAuthentik()
|
const { user, checkSessionStatus } = useAuthentik()
|
||||||
|
const colorMode = useColorMode()
|
||||||
|
|
||||||
|
// Estado del tema
|
||||||
|
const isDark = computed(() => colorMode.value === 'dark')
|
||||||
|
|
||||||
// Obtener la inicial del usuario
|
// Obtener la inicial del usuario
|
||||||
const userInitial = computed(() => {
|
const userInitial = computed(() => {
|
||||||
@@ -42,6 +71,21 @@ const userInitial = computed(() => {
|
|||||||
return name.charAt(0).toUpperCase()
|
return name.charAt(0).toUpperCase()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Cambiar tema
|
||||||
|
const toggleTheme = () => {
|
||||||
|
colorMode.preference = isDark.value ? 'light' : 'dark'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ir al home del ecosistema
|
||||||
|
const goToHome = () => {
|
||||||
|
window.open('https://inicio.nucleoriofrio.com', '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar estado de sesión
|
||||||
|
const handleCheckSession = async () => {
|
||||||
|
await checkSessionStatus()
|
||||||
|
}
|
||||||
|
|
||||||
// Manejar logout
|
// Manejar logout
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
// Redirigir al endpoint de logout de Authentik
|
// Redirigir al endpoint de logout de Authentik
|
||||||
@@ -63,6 +107,7 @@ const handleLogout = () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background-color: color-mix(in srgb, var(--cata-primary) 5%, transparent);
|
background-color: color-mix(in srgb, var(--cata-primary) 5%, transparent);
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .user-avatar {
|
.dark .user-avatar {
|
||||||
@@ -70,6 +115,15 @@ const handleLogout = () => {
|
|||||||
box-shadow: 0 0 8px color-mix(in srgb, var(--cata-primary) 20%, transparent);
|
box-shadow: 0 0 8px color-mix(in srgb, var(--cata-primary) 20%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-avatar:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--cata-primary) 10%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .user-avatar:hover {
|
||||||
|
background-color: color-mix(in srgb, var(--cata-primary) 15%, transparent);
|
||||||
|
box-shadow: 0 0 12px color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive adjustments */
|
/* Responsive adjustments */
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
|
|||||||
12
nuxt4/app/pages/index.vue.backup-20251018
Normal file
12
nuxt4/app/pages/index.vue.backup-20251018
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// Redirigir automáticamente al sistema de catación
|
||||||
|
definePageMeta({
|
||||||
|
middleware: () => {
|
||||||
|
return navigateTo('/cata', { replace: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user