Actividad, se pusieron objeciones NO validadas por el cliente.

This commit is contained in:
Salvador Martínez Gaytán 2025-12-10 19:54:21 -06:00
parent d1a7de1c12
commit 26c6c32de5
20 changed files with 552 additions and 1 deletions

View File

@ -0,0 +1,551 @@
<script src="js/QuizManager.min.js"></script>
<style>
.fake {
background-image: url("img/actividad/fondo-inicio.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed;
}
.fakedesarrollo {
background-image: url("img/actividad/fondo-inicio.jpg");
}
.fakecierre {
background-image: none;
}
.page-activity {
display: none;
}
#inicio {
display: flex;
}
#quiz-container {
margin-top: 20px;
}
.results {
text-align: center;
}
.results h2 {
margin-bottom: 20px;
}
.swal2-popup.swal2-show.pop-retro {
background-color: transparent !important;
background: transparent !important;
border-radius: 0;
border: 0;
}
.custom-card {
border-radius: 15px;
box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
}
#desarrollo {
min-height: 100%;
display: flex;
flex-direction: column;
display: none;
}
.trophy img {
max-width: 100%;
height: auto;
}
.asesor {
margin-top: 0;
max-width: 70px;
}
.pregunta {
color: var(--bs-primary);
text-align: center;
}
/* ============================================================================================================================
== PINCHED SPEECH BUBBLE (more CSS3)
** ============================================================================================================================ */
.pinched {
position: relative;
padding: 15px;
margin: 50px 0 3em;
text-align: center;
color: #fff;
background: #333;
/* css3 */
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
/* creates a rectangle of the colour wanted for the pointy bit */
.pinched:before {
content: "";
position: absolute;
top: -20px;
left: 50%;
width: 100px;
height: 20px;
margin: 0 0 0 -50px;
background: #333;
}
.bubble {
position: relative;
background: #DD3352;
color: #FFFFFF;
box-shadow: 5px 7px 7px -1px rgba(221 51 82 / 30%);
text-align: center;
border-radius: 15px;
padding: 1em;
}
.bubble:after {
content: '';
position: absolute;
display: block;
width: 0;
z-index: 1;
border-style: solid;
border-color: #DD3352 transparent;
border-width: 0 20px 20px;
top: -20px;
left: 50%;
margin-left: -20px;
}
/* En pantallas md (>=768px) mostrar el triángulo apuntando hacia la izquierda */
@media (min-width: 768px) {
.bubble:after {
/* Hacer el triángulo hacia la izquierda: color en el borde derecho */
border-color: transparent #DD3352 transparent transparent;
/* top right bottom left */
border-width: 20px 20px 20px 0;
/* Colocar el triángulo centrado verticalmente y fuera a la izquierda */
top: 50%;
left: -18px;
margin-left: 0;
margin-top: -20px;
}
}
.glass {
/* From https://css.glass */
background: rgba(24, 53, 104, 0.8);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border: 1px solid rgba(24, 53, 104, 0.3);
}
.option-btn {
transition: all .3s ease-in-out;
color: #FFFFFF;
}
.option-btn:hover {
transform: scale(.9);
box-shadow: rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, rgba(10, 37, 64, 0.35) 0px -2px 6px 0px inset !important;
border: 5px solid #DD3352 !important;
}
.bannerend{
width: 100%;
height: auto;
object-fit: cover;
aspect-ratio: 16/5;
max-height: 45dvh;
}
@media (min-width: 1200px) {
.asesor {
margin-top: -90px;
max-width: 200px;
}
.bannerend{
object-position: bottom center;
max-height: 65dvh;
}
}
</style>
<div class="page-sco full-height page-activity" id="inicio">
<div class="container-xxl">
<div class="row justify-content-center align-items-center">
<div class="col-12">
<div class="row justify-content-center align-items-center">
<div class="col-6 col-sm-6 col-md-6 col-xl-4 text-center mt-md-0 mt-4">
<img src="img/actividad/avatar-inicio.png" class="img-fluid floating">
</div>
<div class="col-12 col-sm-12 col-md-6 col-xl-6">
<div class="card custom-card animate__animated animate__fadeInRightBig p-md-4 p-2">
<div class="card-body text-center">
<h1 class="text-primary fw-bold">
¿Quién está diciendo la verdad?
</h1>
En esta actividad podrás practicar cómo responder <span class="fw-bold text-primary">objeciones</span> y elegir quién da la respuesta correcta.<br><br>Prepárate para afinar tu criterio y tomar la mejor
decisión.
</div>
</div>
<div class="w-100 text-center animate__animated animate__slideInDown mt-3">
<div class="btn btn-begin text-white fw-bold py-1 animate__animated animate__pulse animate__infinite disabled" id="btn-comenzar">
Comenzar
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="page-sco page-activity full-height" id="desarrollo" style="display: none;">
<div class="container-xl">
<div class="row align-items-center">
<div class="col-12">
<div class="row align-items-center justify-content-center">
<div class="col-12 col-md-8">
<div class="text-center w-100 d-inline-block p-md-3 p-1 bg-green-2 text-white rounded-3 shadow"><strong>Instrucciones: </strong>Lee la respuesta de los dos representantes sobre una objeción. Analiza
cuidadosamente sus argumentos y elige quién tiene la razón.</div>
</div>
<div class="col-12 col-md-8 col-lg-6">
<div class="row justify-content-center align-items-center my-3">
<div class="trophy col text-center"> <img src="img/actividad/tocheck.png" alt=""> </div>
<div class="trophy col text-center"> <img src="img/actividad/tocheck.png" alt=""> </div>
<div class="trophy col text-center"> <img src="img/actividad/tocheck.png" alt=""> </div>
<div class="trophy col text-center"> <img src="img/actividad/tocheck.png" alt=""> </div>
<div class="trophy col text-center"> <img src="img/actividad/tocheck.png" alt=""> </div>
</div>
</div>
<div class="col-12 col-md-8">
<div id="quiz-container" class="w-100">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="page-sco page-activity full-height" id="cierre" style="display: none;">
<div class="container-fluid p-0 m-0 g-0 passed" style="display: none;">
<img src="img/actividad/bannerbien.jpg" class="bannerend" alt="">
<div class="row align-items-start justify-content-center pt-md-4 pt-2">
<div class="col-12 col-md-8">
<div class="container">
<div class="row">
<div class="col-12 text-center animate__animated animate__fadeInLeft">
<h1 class="fw-bold text-secondary">¡Excelente!</h1>
<p>Has identificado correctamente la mayoría de las afirmaciones.</p>
Tu dominio del contenido de <span class="text-primary fw-bold">OGestan<sup>®</sup> Plus</span> te ayudará a comunicarlo con seguridad.
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container-fluid p-0 m-0 g-0 failed" style="display: none;">
<img src="img/actividad/bannermal.jpg" class="bannerend" alt="">
<div class="row align-items-start justify-content-center pt-md-4 pt-2">
<div class="col-12 col-md-8">
<div class="container">
<div class="row">
<div class="col-12 text-center animate__animated animate__fadeInLeft">
<h1 class="fw-bold text-secondary">¡Vas muy bien!</h1>
<p>Aún puedes mejorar tu precisión. Repasa el contenido y <span class="fw-bold text-primary">vuelve a intentarlo</span>.</p>
<div class="w-100 text-center">
<div class="btn btn-begin text-white fw-bold py-1 animate__animated animate__pulse animate__infinite" onclick="CourseNav.reload()">
Volver a intentar
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(async function () {
// Configuración inicial
$("body").addClass("fake");
$("#loader-course360").show();
// Configuración de las páginas
const pageActivity = ".page-activity";
const pageStart = "#inicio";
const pageDevelopment = "#desarrollo";
const pageSummary = "#cierre";
const audios = {
"inicio": CourseNav.createSound('audio/audiom19.mp3'),
"instrucciones": CourseNav.createSound('audio/audiom20.mp3'),
"correcto": CourseNav.createSound('audio/audiom21.mp3'),
"incorrecto": CourseNav.createSound('audio/audiom22.mp3'),
"fc": CourseNav.createSound('audio/feedback-correct.mp3'),
"fi": CourseNav.createSound('audio/feedback-incorrect.mp3')
}
audios.inicio.on("end", function () {
$("#btn-comenzar").removeClass("disabled");
});
audios.instrucciones.on("end", function () {
$(".btn-open-question").removeClass("disabled grayscale");
});
// Crear instancia de QuizManager
const quizManager = new QuizManager({
excelFileUrl: "manejoDeObjeciones.xlsx",
mandatoryFields: {
question: "pregunta",
correctOption: "opcion_c",
correctFeedback: "retroalimentacion_correcta",
incorrectFeedback: "retroalimentacion_incorrecta",
},
optionPrefix: "opcion", // Prefijo para las opciones
randomizeQuestions: true, // Habilitar preguntas aleatorias
randomizeOptions: true, // Habilitar opciones aleatorias
passingScore: 80, // Puntaje mínimo aprobatorio
defaultWeight: 1, // Ponderación por defecto
maxAttempts: Infinity, // Intentos máximos por defecto
maxQuestions: 5, // Obtener solo 5 preguntas
specialOptions: ["Ninguna de las anteriores", "Todas las anteriores"], // Textos especiales
});
// Configurar intentos iniciales con validación desde el LMS
const attempt = !isNaN(CourseNav.getLessonLocation()) ? Number(CourseNav.getLessonLocation()) : 0;
console.log("Intento actual obtenido del LMS:", attempt);
quizManager.setAttempts(attempt);
if (attempt < 1) {
CourseNav.audioController.stopAllSoundsAndPlay(audios.inicio);
} else {
$("#btn-comenzar").removeClass("disabled");
}
// Cargar las preguntas al inicio
await loadAndStartQuiz();
// Manejar clic en el botón "Comenzar"
$("#btn-comenzar").click(function () {
const maxAttempts = quizManager.config.maxAttempts || Infinity; // Obtener intentos máximos
const attemptsMade = quizManager.getAttempts(); // Intentos realizados
if (!quizManager.hasReachedMaxAttempts()) {
$(pageActivity).hide();
$(pageDevelopment).addClass('d-flex');
// Incrementar los intentos y guardar en el LMS
quizManager.incrementAttempts();
CourseNav.setLessonLocation(quizManager.getAttempts());
$("body").addClass('fakedesarrollo');
CourseNav.audioController.stopAllSoundsAndPlay(audios.instrucciones);
// Renderizar la primera pregunta
renderQuestion("#quiz-container", false);
} else {
// Mostrar mensaje si se alcanzó el límite de intentos
const maxAttemptsTxt = maxAttempts === Infinity ? "&infin;" : maxAttempts;
Swal.fire({
icon: "error",
title: "¡Límite de intentos alcanzado!",
html: `
<p>Has alcanzado el límite de intentos.</p>
<p><strong>Intentos realizados:</strong> ${attemptsMade}</p>
<p><strong>Intentos permitidos:</strong> ${maxAttemptsTxt}</p>
`,
confirmButtonText: "Aceptar",
}).then(() => {
CourseNav.resetCourse();
});
}
});
/**
* Carga las preguntas desde el archivo Excel y muestra el inicio.
*/
async function loadAndStartQuiz() {
try {
await quizManager.loadQuestionsFromExcel();
console.log("Preguntas cargadas exitosamente.");
console.table(quizManager.getAllRenderData());
$("#loader-course360").hide();
} catch (error) {
console.error("Error al cargar las preguntas:", error);
$("#loader-course360").hide(); // Asegurarse de ocultar el loader en caso de error
}
}
/**
* Renderiza la pregunta actual en un contenedor específico o en un Swal.
* @param {string} containerSelector - Selector del contenedor donde se renderizará la pregunta.
* @param {boolean} [useSwal=false] - Si es `true`, muestra la pregunta en un Swal en lugar del contenedor.
*/
function renderQuestion(containerSelector, useSwal = false) {
const questionData = quizManager.getRenderData();
if (questionData) {
const questionHtml = `<div class="row justify-content-center">
<div class="col-12 text-center mb-3">
<div class="row align-items-center justify-content-center">
<div class="col-12 col-md-3 text-center mb-3 mb-md-0"><img src="img/actividad/medico.png" class="img-fluid animate__animated animate__flipInY" alt=""></div>
<div class="col-12 col-md-9 text-center"><div class="w-100 pregunta bubble">${questionData.text}</div></div>
</div>
</div>
<div class="col-12 col-xl-5 animate__animated animate__fadeInLeft">
<div class="card glass border-0 rounded-15 shadow option-btn cursor h-100 p-1 p-md-3" data-correct="${questionData.options[0].isCorrect}">
<div class="card-body text-center d-inline-flex flex-xl-column flex-row justify-content-center align-items-center p-1 p-md-3">
<img src="img/actividad/atenciona.png" class="img-fluid asesor" alt="">
<div class="w-100 opcion text-md-center text-start">${questionData.options[0].text}</div>
</div>
</div>
</div>
<div class="col-12 col-xl-2 my-xl-5 my-3 text-center animate__animated animate__bounceIn animate__delay-1s">
<img src="img/actividad/vs.png" class="img-fluid d-xl-inline-block d-none" alt="">
<img src="img/actividad/vsmd.png" class="img-fluid d-xl-none d-inline-block" alt="">
</div>
<div class="col-12 col-xl-5 animate__animated animate__fadeInRight">
<div class="card glass border-0 rounded-15 shadow option-btn cursor h-100 p-1 p-md-3" data-correct="${questionData.options[1].isCorrect}">
<div class="card-body text-center d-inline-flex flex-xl-column flex-row justify-content-center align-items-center p-1 p-md-3">
<img src="img/actividad/atencionb.png" class="img-fluid asesor" alt="">
<div class="w-100 opcion text-md-center text-start">${questionData.options[1].text}</div>
</div>
</div>
</div>
</div>`;
if (useSwal) {
// Mostrar la pregunta en un Swal
Swal.fire({
html: questionHtml,
showConfirmButton: false,
customClass: { popup: "swal-question-popup" },
backdrop: "rgba(65, 60, 60, .95)",
showDenyButton: false,
showCancelButton: false,
allowOutsideClick: false,
allowEscapeKey: false,
focusConfirm: false,
target: document.getElementById('coursenav-main-content'),
didOpen: () => {
const swalContent = Swal.getHtmlContainer(); // Obtiene el contenedor HTML actual de Swal
// Eliminar cualquier controlador anterior para evitar duplicados
$(swalContent)
.find(".option-btn")
.off("click")
.on("click", function () {
const isCorrect = $(this).data("correct") === "true";
const feedback = isCorrect
? questionData.correctFeedback || "¡Correcto!"
: questionData.incorrectFeedback || "Incorrecto";
handleFeedback(isCorrect, feedback, containerSelector, true); // Usar función para manejar retroalimentación
});
},
});
} else {
// Renderizar pregunta en el contenedor HTML
$(containerSelector).html(questionHtml);
// Eliminar cualquier controlador anterior en el contenedor antes de agregar nuevos
$(containerSelector).off("click", ".option-btn");
// Manejar clic en las opciones
$(containerSelector).on("click", ".option-btn", function () {
const isCorrect = $(this).data("correct") === true;
const feedback = isCorrect
? questionData.correctFeedback || "¡Correcto!"
: questionData.incorrectFeedback || "Incorrecto";
handleFeedback(isCorrect, feedback, containerSelector, false); // Usar función para manejar retroalimentación
});
}
}
}
/**
* Maneja la retroalimentación de la respuesta del usuario y realiza acciones posteriores.
* @param {boolean} isCorrect - Indica si la respuesta del usuario es correcta.
* @param {string} feedback - El texto de retroalimentación que se mostrará.
* @param {string} containerSelector - Selector del contenedor o Swal para renderizar la siguiente pregunta.
* @param {boolean} useSwal - Si es `true`, las preguntas se muestran en un Swal.
*/
function handleFeedback(isCorrect, feedback, containerSelector, useSwal) {
const imageName = isCorrect ? 'retrobien.png' : 'retromal.png';
const html = `<div class="text-center w-100 overflow-hidden">
<img src="img/actividad/${imageName}" class="img-fluid animate__animated animate__flipInY">
<p class="text-white">${feedback}</p>
</div>`;
if (isCorrect) {
CourseNav.audioController.stopAllSoundsAndPlay(audios.fc);
} else {
CourseNav.audioController.stopAllSoundsAndPlay(audios.fi);
}
Swal.fire({
html: html,
showConfirmButton: true,
confirmButtonText: "Cerrar",
backdrop: "rgba(14, 28, 98, .9)",
showCloseButton: false,
target: document.getElementById('coursenav-main-content'),
customClass: {
popup: 'w-32em pop-retro',
confirmButton: 'btn btn-begin text-white fw-bold py-1 animate__animated animate__pulse animate__infinite'
},
}).then(() => {
updateVisualFeedback(isCorrect); // Actualiza visualización
quizManager.answerCurrentQuestion(isCorrect); // Registra respuesta
// Mostrar siguiente pregunta o resultados finales
if (quizManager.hasMoreQuestions()) {
quizManager.getNextQuestion();
renderQuestion(containerSelector, false); // Renderizar la siguiente pregunta
} else {
renderResults("#resume-container"); // Mostrar resultados finales
}
});
}
/**
* Renderiza los resultados finales en un contenedor específico.
* @param {string} containerSelector - Selector del contenedor donde se renderizarán los resultados.
*/
function renderResults(containerSelector) {
$(pageActivity).hide().removeClass("d-flex");
$(pageSummary).show().addClass("d-flex");
$("body").addClass("fakecierre");
const summary = quizManager.getSummary();
const maxAttempts = quizManager.config.maxAttempts || Infinity; // Intentos máximos desde la configuración
const maxAttemptsTxt = maxAttempts === Infinity ? "&infin;" : maxAttempts;
if (summary.passed) {
CourseNav.audioController.stopAllSoundsAndPlay(audios.correcto);
$(".passed").show();
CourseNav.setSlideVisited();
} else {
$(".failed").show();
CourseNav.audioController.stopAllSoundsAndPlay(audios.incorrecto);
}
}
function updateVisualFeedback(isCorrect) {
if (isCorrect) {
$(".trophy").eq(quizManager.currentQuestionIndex).addClass("win");
$(".trophy").eq(quizManager.currentQuestionIndex).find("img").attr('src', 'img/actividad/check.png').addClass("win");
} else {
$(".trophy").eq(quizManager.currentQuestionIndex).find("img").attr('src', 'img/actividad/uncheck.png');
}
}
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -6,7 +6,7 @@
*/
window.COURSE_CONFIG = {
COURSE_CONFIG_URL: 'config.json',
DEBUG: false,
DEBUG: true,
SHOW_PAGINATION: false, // Bandera para mostrar/ocultar paginación
SHOW_TITLE: false, // Bandera para mostrar/ocultar título
SHOW_GLOSSARY: false, // Bandera para mostrar/ocultar glosario

Binary file not shown.