Este proyecto implementa un formulario dinámico de encuestas/diagnóstico basado en Vue/Nuxt 3, que permite:
- Navegar entre pantallas o slices (bienvenida, preguntas, feedback, resultados).
- Guardar las respuestas del usuario y su progreso en
localStorage. - Calcular resultados por bloque y un resultado final con recomendaciones.
- Adaptar el flujo de navegación de forma lineal o condicional según la configuración.
El formulario se compone de:
- Un archivo principal (
index.vue) → Controla el flujo de navegación, almacenamiento de respuestas y cálculo de resultados. - Un objeto de configuración (
surveyData) → Define todas las pantallas (slices) de la encuesta, las reglas de evaluación y las recomendaciones finales. Proviene de un archivo .js - Componentes de presentación → (
SliceWelcome,SliceQuestion,SliceFeedback,SliceEnd), que renderizan cada tipo de pantalla.
- El usuario ve la pantalla de bienvenida (welcome).
- Responde preguntas de un bloque (question).
- Recibe un feedback parcial (feedback) con recomendaciones.
- Repite el proceso en los siguientes bloques.
- Llega a la pantalla final (end) con un diagnóstico completo y recomendaciones globales.
El archivo index.vue cumple el rol de motor del formulario.
data() {
return {
surveyData, // Definición de la encuesta
currentSliceId: surveyData.slices[0].id, // Controla qué pantalla se está mostrando
answers: [], // Respuestas del usuario
score: null, // Puntuación final
results: null // Resultados por bloque
}
}El formulario muestra un slice a la vez, definido en surveyData.slices y según el type, el sistema selecciona qué componente visual debe renderizarse.
computed: {
currentSlice() {
return surveyData.slices.find(s => s.id === this.currentSliceId)
},
currentSliceComponent() {
switch (this.currentSlice.type) {
case "welcome": return "SliceWelcome"
case "question": return "SliceQuestion"
case "feedback": return "SliceFeedback"
case "end": return "SliceEnd"
default: return "SliceQuestion"
}
}
}La navegación entre slices se define en la propiedad next de cada slice.
- Lineal: lleva directamente al siguiente slice.
"next": "B0-02"- Condicional: el siguiente slice depende de la respuesta del usuario.
"next": { "yes": "Q2", "no": "Q3" }Los métodos principales son:
goToNext(event)Guarda el historial de slices visitados en localStorage (previous-slices).goToPrevious()Permite volver atrás eliminando la última respuesta y restaurando el slice previo.
Cada vez que el usuario responde una pregunta, se construye un objeto de respuesta:
{
sectionId, // ID del bloque (ej. B0)
sectionTitle, // Título del bloque
sliceId, // ID de la pregunta
value, // Valor elegido
score, // Puntuación obtenida
questionTotalPoints // Puntos posibles en la pregunta
}Estas respuestas se guardan en memoria (answers) y en localStorage.
Cuando el usuario llega a un slice de tipo feedback, se calcula la puntuación del bloque calculateBlockResult()
- Filtra las respuestas de la sección actual (sectionId).
- Suma los puntajes obtenidos.
- Calcula los puntos máximos posibles del bloque.
- Evalúa el resultado aplicando la regla definida en
surveyData.rules. - Guarda los resultados parciales en
localStorage.
Ejemplo de resultado guardado:
{
"sectionId": "B0",
"sectionTitle": "Estrategia y gobernanza",
"sectionPossibleTotalPoints": 15,
"score": 10,
"result": "Revisar y actualizar la política de sostenibilidad..."
}En el último slice (end), se ejecuta calculateFinalScore()
- Suma todos los resultados parciales.
- Calcula el total de puntos posibles.
- Aplica la regla de surveyData.finalRecommendations.total(score).
- Guarda el resultado en localStorage.
Ejemplo de resultado final:
{
"totalPossiblePoints": 75,
"score": 42,
"recommendations": "B Corp, ISO 14001, ISO 45001"
}El archivo surveyData.js define la encuesta completa.
export const surveyData = {
title: "Formulario Demo",
slices: [ ... ], // Definición de pantallas
rules: { ... }, // Reglas de evaluación por bloque
finalRecommendations: { ... } // Reglas de evaluación global
}Cada slice tiene un tipo (type), que determina el componente a renderizar.
- welcome → pantalla de bienvenida.
- question → una pregunta con opciones de respuesta.
- feedback → resultados de un bloque de preguntas.
- end → pantalla final con diagnóstico.
{
id: "B0-01",
type: "question",
section: { id: "B0", title: "1. Estrategia y gobernanza" },
question: {
title: "¿Cuenta con una memoria de sostenibilidad?",
description: "1 es la puntuación más baja y 5 la más alta."
},
input: {
type: "range",
options: [
{ value: "1", label: "1", score: 1 },
{ value: "2", label: "2", score: 2 },
...
]
},
questionTotalPoints: 5,
next: "B0-02"
}Cada bloque (B0, B1, …) tiene una función que evalúa el puntaje:
rules: {
B0: (score) => score <= 2
? "Recomendaciones básicas..."
: "Recomendaciones avanzadas...",
...
}En finalRecommendations, se evalúa el puntaje global:
finalRecommendations: {
total: (score) => {
if (score <= 25) return "Certificado regional..."
if (score <= 40) return "B Corp, ISO 14001..."
return "GRI verificado..."
}
}