Feat: Implementar SCAA Score y conversión bidireccional
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
CAMBIOS PRINCIPALES: 1. Nueva fórmula de SCAA Score: - S = 0.65625 × Σhᵢ + 52.75 - 2u - 4d - Donde hᵢ = puntaje afectivo (1-9) - u = tazas no uniformes, d = tazas defectuosas 2. Funciones de cálculo (catacion.ts): - calcularSumatoriaAfectiva(): suma de valores afectivos - calcularSCAA(): calcula SCAA Score con penalizaciones - scaaASumatoriaAfectiva(): conversión inversa (sin penalizaciones) - sumatoriaAfectivaASCAA(): conversión directa (sin penalizaciones) 3. FormularioMuestra.vue: - Mostrar ambos scores en el acordeón - "Sumatoria Afectiva" (entero, suma de afectivos) - "SCAA Score" (decimal, con 2 decimales) 4. ModalAsignacionRapida.vue: - Doble input: Sumatoria Afectiva + SCAA Score - Sincronización bidireccional automática - Al modificar Sumatoria → actualiza SCAA - Al modificar SCAA → calcula Sumatoria más cercana - Validación y redondeo para mantener enteros válidos - Rango: Sumatoria 9-90, SCAA 58.65-112.00 NOTAS: - En asignación rápida no se toman en cuenta penalizaciones - SCAA Score acepta decimales, Sumatoria solo enteros - Múltiples SCAA Scores pueden apuntar al mismo entero
This commit is contained in:
@@ -801,16 +801,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Puntaje Final (solo lectura) -->
|
<!-- Puntajes (solo lectura) -->
|
||||||
<div class="global-section p-4 cata-outline-box rounded-lg">
|
<div class="global-section p-4 cata-outline-box rounded-lg space-y-4">
|
||||||
<div class="puntaje-final">
|
<!-- Sumatoria Afectiva -->
|
||||||
|
<div class="puntaje-item">
|
||||||
<div class="flex items-baseline justify-between">
|
<div class="flex items-baseline justify-between">
|
||||||
<span class="text-sm cata-text opacity-75">Puntaje Final:</span>
|
<span class="text-sm cata-text opacity-75">Sumatoria Afectiva:</span>
|
||||||
<span class="text-3xl font-bold cata-text">{{ muestra.puntajeFinal }}</span>
|
<span class="text-2xl font-bold cata-text">{{ sumatoriaAfectiva }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SCAA Score -->
|
||||||
|
<div class="puntaje-item">
|
||||||
|
<div class="flex items-baseline justify-between">
|
||||||
|
<span class="text-sm cata-text opacity-75">SCAA Score:</span>
|
||||||
|
<span class="text-3xl font-bold cata-text">{{ scaaScore.toFixed(2) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs cata-text opacity-60 mt-1">
|
|
||||||
Suma de valores afectivos
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -820,7 +826,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Muestra, NotaSeleccionada, TipoDefecto, SensacionBoca, GustoPredominante } from '~/types/catacion'
|
import type { Muestra, NotaSeleccionada, TipoDefecto, SensacionBoca, GustoPredominante } from '~/types/catacion'
|
||||||
import type { TabCatacion, Subcategoria } from '~/composables/useCatacion'
|
import type { TabCatacion, Subcategoria } from '~/composables/useCatacion'
|
||||||
import { SENSACIONES_BOCA, GUSTOS_PREDOMINANTES, TIPOS_DEFECTOS } from '~/types/catacion'
|
import { SENSACIONES_BOCA, GUSTOS_PREDOMINANTES, TIPOS_DEFECTOS, calcularSumatoriaAfectiva, calcularSCAA } from '~/types/catacion'
|
||||||
|
|
||||||
interface FormularioMuestraProps {
|
interface FormularioMuestraProps {
|
||||||
/** Muestra a editar */
|
/** Muestra a editar */
|
||||||
@@ -858,6 +864,10 @@ const sensacionesBoca = SENSACIONES_BOCA
|
|||||||
const gustosPredominantes = GUSTOS_PREDOMINANTES
|
const gustosPredominantes = GUSTOS_PREDOMINANTES
|
||||||
const tiposDefectos = TIPOS_DEFECTOS
|
const tiposDefectos = TIPOS_DEFECTOS
|
||||||
|
|
||||||
|
// Cálculos de puntajes
|
||||||
|
const sumatoriaAfectiva = computed(() => calcularSumatoriaAfectiva(props.muestra))
|
||||||
|
const scaaScore = computed(() => calcularSCAA(props.muestra))
|
||||||
|
|
||||||
// Helpers para filtrado por subcategorías
|
// Helpers para filtrado por subcategorías
|
||||||
const deberMostrarSeccion = (subcategorias: Subcategoria[]): boolean => {
|
const deberMostrarSeccion = (subcategorias: Subcategoria[]): boolean => {
|
||||||
// Si no hay filtros activos, mostrar todo
|
// Si no hay filtros activos, mostrar todo
|
||||||
|
|||||||
@@ -22,17 +22,42 @@
|
|||||||
<template #body>
|
<template #body>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<!-- Paso 1: Ingresar puntaje total deseado -->
|
<!-- Paso 1: Ingresar puntaje total deseado -->
|
||||||
<div v-if="paso === 1">
|
<div v-if="paso === 1" class="space-y-3">
|
||||||
|
<!-- Input de Sumatoria Afectiva -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs cata-text opacity-75 mb-1 text-center">
|
||||||
|
Sumatoria Afectiva
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
v-model.number="puntajeDeseado"
|
v-model.number="puntajeDeseado"
|
||||||
type="number"
|
type="number"
|
||||||
:min="9"
|
:min="9"
|
||||||
:max="90"
|
:max="90"
|
||||||
placeholder="Puntaje Total (9-90)"
|
step="1"
|
||||||
|
placeholder="9-90"
|
||||||
class="cata-input w-full px-3 py-2 rounded-md text-center text-lg"
|
class="cata-input w-full px-3 py-2 rounded-md text-center text-lg"
|
||||||
|
@input="onSumatoriaChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Input de SCAA Score -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs cata-text opacity-75 mb-1 text-center">
|
||||||
|
SCAA Score
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model.number="scaaDeseado"
|
||||||
|
type="number"
|
||||||
|
:min="scaaMin"
|
||||||
|
:max="scaaMax"
|
||||||
|
step="0.01"
|
||||||
|
placeholder="58.65-112.00"
|
||||||
|
class="cata-input w-full px-3 py-2 rounded-md text-center text-lg"
|
||||||
|
@input="onScaaChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Paso 2: Seleccionar categorías que sobresalen o palidecen -->
|
<!-- Paso 2: Seleccionar categorías que sobresalen o palidecen -->
|
||||||
<div v-if="paso === 2">
|
<div v-if="paso === 2">
|
||||||
<!-- Subtítulo con icono y contador -->
|
<!-- Subtítulo con icono y contador -->
|
||||||
@@ -121,6 +146,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Muestra } from '~/types/catacion'
|
import type { Muestra } from '~/types/catacion'
|
||||||
|
import { scaaASumatoriaAfectiva, sumatoriaAfectivaASCAA } from '~/types/catacion'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue: boolean
|
modelValue: boolean
|
||||||
@@ -155,17 +181,70 @@ const isOpen = computed({
|
|||||||
// Estado del formulario
|
// Estado del formulario
|
||||||
const paso = ref(1)
|
const paso = ref(1)
|
||||||
const puntajeDeseado = ref<number>(45)
|
const puntajeDeseado = ref<number>(45)
|
||||||
|
const scaaDeseado = ref<number>(sumatoriaAfectivaASCAA(45))
|
||||||
const categoriasSeleccionadas = ref<string[]>([])
|
const categoriasSeleccionadas = ref<string[]>([])
|
||||||
|
|
||||||
|
// Flag para evitar loops infinitos en la sincronización
|
||||||
|
const actualizandoInput = ref(false)
|
||||||
|
|
||||||
|
// Límites de SCAA Score (basados en sumatoria afectiva 9-90)
|
||||||
|
const scaaMin = sumatoriaAfectivaASCAA(9)
|
||||||
|
const scaaMax = sumatoriaAfectivaASCAA(90)
|
||||||
|
|
||||||
// Resetear estado cuando el modal se abre
|
// Resetear estado cuando el modal se abre
|
||||||
watch(isOpen, (newValue) => {
|
watch(isOpen, (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
paso.value = 1
|
paso.value = 1
|
||||||
puntajeDeseado.value = 45
|
puntajeDeseado.value = 45
|
||||||
|
scaaDeseado.value = sumatoriaAfectivaASCAA(45)
|
||||||
categoriasSeleccionadas.value = []
|
categoriasSeleccionadas.value = []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Handler para cuando se modifica Sumatoria Afectiva
|
||||||
|
const onSumatoriaChange = () => {
|
||||||
|
if (actualizandoInput.value) return
|
||||||
|
|
||||||
|
actualizandoInput.value = true
|
||||||
|
|
||||||
|
// Validar rango
|
||||||
|
if (puntajeDeseado.value < 9) puntajeDeseado.value = 9
|
||||||
|
if (puntajeDeseado.value > 90) puntajeDeseado.value = 90
|
||||||
|
|
||||||
|
// Redondear a entero
|
||||||
|
puntajeDeseado.value = Math.round(puntajeDeseado.value)
|
||||||
|
|
||||||
|
// Actualizar SCAA Score
|
||||||
|
scaaDeseado.value = sumatoriaAfectivaASCAA(puntajeDeseado.value)
|
||||||
|
|
||||||
|
actualizandoInput.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler para cuando se modifica SCAA Score
|
||||||
|
const onScaaChange = () => {
|
||||||
|
if (actualizandoInput.value) return
|
||||||
|
|
||||||
|
actualizandoInput.value = true
|
||||||
|
|
||||||
|
// Validar rango
|
||||||
|
if (scaaDeseado.value < scaaMin) scaaDeseado.value = scaaMin
|
||||||
|
if (scaaDeseado.value > scaaMax) scaaDeseado.value = scaaMax
|
||||||
|
|
||||||
|
// Convertir a Sumatoria Afectiva
|
||||||
|
const sumatoriaCalculada = scaaASumatoriaAfectiva(scaaDeseado.value)
|
||||||
|
|
||||||
|
// Redondear al entero más cercano (sumatoria afectiva debe ser entero)
|
||||||
|
const sumatoriaRedondeada = Math.round(sumatoriaCalculada)
|
||||||
|
|
||||||
|
// Asegurar rango válido
|
||||||
|
puntajeDeseado.value = Math.max(9, Math.min(90, sumatoriaRedondeada))
|
||||||
|
|
||||||
|
// Recalcular SCAA Score con el valor redondeado
|
||||||
|
scaaDeseado.value = sumatoriaAfectivaASCAA(puntajeDeseado.value)
|
||||||
|
|
||||||
|
actualizandoInput.value = false
|
||||||
|
}
|
||||||
|
|
||||||
// Cálculos
|
// Cálculos
|
||||||
const puntajeValido = computed(() => {
|
const puntajeValido = computed(() => {
|
||||||
return puntajeDeseado.value >= 9 && puntajeDeseado.value <= 90
|
return puntajeDeseado.value >= 9 && puntajeDeseado.value <= 90
|
||||||
|
|||||||
@@ -190,9 +190,9 @@ export function crearMuestraVacia(id: number): Muestra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calcula el puntaje final sumando todos los valores afectivos
|
* Calcula la sumatoria afectiva sumando todos los valores afectivos
|
||||||
*/
|
*/
|
||||||
export function calcularPuntajeFinal(muestra: Muestra): number {
|
export function calcularSumatoriaAfectiva(muestra: Muestra): number {
|
||||||
const { intensidades } = muestra
|
const { intensidades } = muestra
|
||||||
let total = 0
|
let total = 0
|
||||||
|
|
||||||
@@ -206,6 +206,42 @@ export function calcularPuntajeFinal(muestra: Muestra): number {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el puntaje final (sumatoria afectiva) - alias para compatibilidad
|
||||||
|
*/
|
||||||
|
export function calcularPuntajeFinal(muestra: Muestra): number {
|
||||||
|
return calcularSumatoriaAfectiva(muestra)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcula el SCAA Score a partir de la muestra
|
||||||
|
* Fórmula: S = 0.65625 × Σhᵢ + 52.75 - 2u - 4d
|
||||||
|
* donde hᵢ = puntaje afectivo (1-9), u = tazas no uniformes, d = tazas defectuosas
|
||||||
|
*/
|
||||||
|
export function calcularSCAA(muestra: Muestra): number {
|
||||||
|
const sumatoriaAfectiva = calcularSumatoriaAfectiva(muestra)
|
||||||
|
const u = muestra.tazasNoUniformes.length
|
||||||
|
const d = muestra.tazasDefectuosas.length
|
||||||
|
|
||||||
|
return 0.65625 * sumatoriaAfectiva + 52.75 - 2 * u - 4 * d
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convierte un SCAA Score a Sumatoria Afectiva (sin penalizaciones)
|
||||||
|
* Fórmula inversa: Σhᵢ = (S - 52.75) / 0.65625
|
||||||
|
*/
|
||||||
|
export function scaaASumatoriaAfectiva(scaaScore: number): number {
|
||||||
|
return (scaaScore - 52.75) / 0.65625
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convierte Sumatoria Afectiva a SCAA Score (sin penalizaciones)
|
||||||
|
* Fórmula: S = 0.65625 × Σhᵢ + 52.75
|
||||||
|
*/
|
||||||
|
export function sumatoriaAfectivaASCAA(sumatoriaAfectiva: number): number {
|
||||||
|
return 0.65625 * sumatoriaAfectiva + 52.75
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crea una sesión de catación vacía
|
* Crea una sesión de catación vacía
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user