186 lines
9.2 KiB
HTML
186 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>OpoQuizTiny - Copilot Fase 3</title>
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; margin: 0; padding: 2em; background: #f8f9fa; }
|
|
h1 { font-size: 2em; margin-bottom: 0.5em; }
|
|
.file-input, .config-form { margin-bottom: 1em; }
|
|
.json-list { background: #fff; border: 1px solid #ccc; padding: 1em; border-radius: 6px; margin-top: 1em; }
|
|
pre { background: #f4f4f4; padding: 1em; border-radius: 4px; overflow-x: auto; }
|
|
.error { color: #b00; margin-top: 1em; }
|
|
.config-form label { display: block; margin-top: 0.5em; }
|
|
.config-form input, .config-form select { margin-top: 0.2em; }
|
|
.config-summary { background: #e9f7ef; border: 1px solid #b2dfdb; padding: 1em; border-radius: 6px; margin-top: 1em; }
|
|
.quiz-section { background: #fffde7; border: 1px solid #ffe082; padding: 1em; border-radius: 6px; margin-top: 1em; }
|
|
.question { margin-bottom: 1em; }
|
|
.answers { margin-bottom: 1em; }
|
|
.result { background: #e1f5fe; border: 1px solid #81d4fa; padding: 1em; border-radius: 6px; margin-top: 1em; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>OpoQuizTiny <small style="font-size:0.5em;">(Copilot Fase 3)</small></h1>
|
|
<form id="jsonForm" class="file-input">
|
|
<label for="jsonFiles">Cargar archivos JSON de temario:</label>
|
|
<input type="file" id="jsonFiles" name="jsonFiles" accept=".json" multiple>
|
|
</form>
|
|
<form id="configForm" class="config-form">
|
|
<label for="numQuestions">Número de preguntas:</label>
|
|
<input type="number" id="numQuestions" name="numQuestions" min="1" max="50" value="10">
|
|
<label for="questionType">Tipo de preguntas:</label>
|
|
<select id="questionType" name="questionType">
|
|
<option value="vf">Verdadero/Falso</option>
|
|
<option value="single">Opción única</option>
|
|
<option value="multi">Multiselección</option>
|
|
</select>
|
|
<label for="numAnswers">Número de respuestas por pregunta:</label>
|
|
<input type="number" id="numAnswers" name="numAnswers" min="2" max="10" value="4">
|
|
<label for="jsonSelect">Seleccionar temario cargado:</label>
|
|
<select id="jsonSelect" name="jsonSelect" multiple></select>
|
|
<button type="submit">Guardar configuración</button>
|
|
</form>
|
|
<div id="configSummary" class="config-summary" style="display:none;"></div>
|
|
<div id="quizSection" class="quiz-section" style="display:none;"></div>
|
|
<div id="output" class="json-list"></div>
|
|
<div id="error" class="error"></div>
|
|
<script>
|
|
let loadedJsons = {};
|
|
let quizConfig = null;
|
|
document.getElementById('jsonFiles').addEventListener('change', function (e) {
|
|
const files = Array.from(e.target.files);
|
|
const output = document.getElementById('output');
|
|
const error = document.getElementById('error');
|
|
const jsonSelect = document.getElementById('jsonSelect');
|
|
output.innerHTML = '';
|
|
error.textContent = '';
|
|
jsonSelect.innerHTML = '';
|
|
loadedJsons = {};
|
|
if (!files.length) return;
|
|
files.forEach(file => {
|
|
const reader = new FileReader();
|
|
reader.onload = function(evt) {
|
|
try {
|
|
const json = JSON.parse(evt.target.result);
|
|
loadedJsons[file.name] = json;
|
|
output.innerHTML += `<h3>${file.name}</h3><pre>${JSON.stringify(json, null, 4)}</pre>`;
|
|
const option = document.createElement('option');
|
|
option.value = file.name;
|
|
option.textContent = file.name;
|
|
jsonSelect.appendChild(option);
|
|
} catch (err) {
|
|
error.textContent = `Error en "${file.name}": ${err.message}`;
|
|
}
|
|
};
|
|
reader.onerror = function() {
|
|
error.textContent = `No se pudo leer el archivo "${file.name}".`;
|
|
};
|
|
reader.readAsText(file, 'utf-8');
|
|
});
|
|
});
|
|
document.getElementById('configForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const numQuestions = parseInt(document.getElementById('numQuestions').value);
|
|
const questionType = document.getElementById('questionType').value;
|
|
const numAnswers = parseInt(document.getElementById('numAnswers').value);
|
|
const jsonSelect = document.getElementById('jsonSelect');
|
|
const selectedJsons = Array.from(jsonSelect.selectedOptions).map(opt => opt.value);
|
|
const configSummary = document.getElementById('configSummary');
|
|
if (selectedJsons.length === 0) {
|
|
configSummary.style.display = 'none';
|
|
alert('Selecciona al menos un temario cargado.');
|
|
return;
|
|
}
|
|
quizConfig = { numQuestions, questionType, numAnswers, selectedJsons };
|
|
configSummary.innerHTML = `<strong>Configuración guardada:</strong><br>
|
|
Número de preguntas: ${numQuestions}<br>
|
|
Tipo de preguntas: ${questionType}<br>
|
|
Número de respuestas: ${numAnswers}<br>
|
|
Temarios seleccionados: ${selectedJsons.join(', ')}`;
|
|
configSummary.style.display = 'block';
|
|
generarQuiz();
|
|
});
|
|
function generarQuiz() {
|
|
const quizSection = document.getElementById('quizSection');
|
|
quizSection.innerHTML = '';
|
|
quizSection.style.display = 'block';
|
|
// Recopilar todos los nodos del temario seleccionado
|
|
let nodos = [];
|
|
quizConfig.selectedJsons.forEach(name => {
|
|
const json = loadedJsons[name];
|
|
if (Array.isArray(json)) {
|
|
nodos = nodos.concat(json);
|
|
} else if (typeof json === 'object') {
|
|
nodos.push(json);
|
|
}
|
|
});
|
|
// Generar preguntas aleatorias
|
|
const preguntas = [];
|
|
for (let i = 0; i < quizConfig.numQuestions; i++) {
|
|
const nodo = nodos[Math.floor(Math.random() * nodos.length)];
|
|
let pregunta = '';
|
|
let respuestas = [];
|
|
if (quizConfig.questionType === 'vf') {
|
|
pregunta = `¿${nodo.name ? (Array.isArray(nodo.name) ? nodo.name[0] : nodo.name) : 'Sin nombre'} es verdadero?`;
|
|
respuestas = ['Verdadero', 'Falso'];
|
|
} else if (quizConfig.questionType === 'single') {
|
|
pregunta = `¿Cuál es la descripción de ${nodo.name ? (Array.isArray(nodo.name) ? nodo.name[0] : nodo.name) : 'Sin nombre'}?`;
|
|
respuestas = [nodo.description ? (Array.isArray(nodo.description) ? nodo.description[0] : nodo.description) : 'Sin descripción'];
|
|
while (respuestas.length < quizConfig.numAnswers) {
|
|
respuestas.push('Opción incorrecta ' + respuestas.length);
|
|
}
|
|
} else if (quizConfig.questionType === 'multi') {
|
|
pregunta = `Selecciona las opciones correctas sobre ${nodo.name ? (Array.isArray(nodo.name) ? nodo.name[0] : nodo.name) : 'Sin nombre'}`;
|
|
respuestas = [];
|
|
if (nodo.description) {
|
|
if (Array.isArray(nodo.description)) {
|
|
respuestas = respuestas.concat(nodo.description);
|
|
} else {
|
|
respuestas.push(nodo.description);
|
|
}
|
|
}
|
|
while (respuestas.length < quizConfig.numAnswers) {
|
|
respuestas.push('Opción incorrecta ' + respuestas.length);
|
|
}
|
|
}
|
|
preguntas.push({ pregunta, respuestas });
|
|
}
|
|
// Renderizar preguntas
|
|
preguntas.forEach((q, idx) => {
|
|
const div = document.createElement('div');
|
|
div.className = 'question';
|
|
div.innerHTML = `<strong>Pregunta ${idx + 1}:</strong> ${q.pregunta}`;
|
|
const answersDiv = document.createElement('div');
|
|
answersDiv.className = 'answers';
|
|
q.respuestas.forEach((ans, i) => {
|
|
let inputType = quizConfig.questionType === 'multi' ? 'checkbox' : 'radio';
|
|
answersDiv.innerHTML += `<label><input type="${inputType}" name="q${idx}" value="${ans}"> ${ans}</label><br>`;
|
|
});
|
|
div.appendChild(answersDiv);
|
|
quizSection.appendChild(div);
|
|
});
|
|
// Botón para corregir
|
|
const btn = document.createElement('button');
|
|
btn.textContent = 'Corregir';
|
|
btn.onclick = function() {
|
|
mostrarResultados(preguntas);
|
|
};
|
|
quizSection.appendChild(btn);
|
|
}
|
|
function mostrarResultados(preguntas) {
|
|
const quizSection = document.getElementById('quizSection');
|
|
let resultado = '<div class="result"><strong>Resultados:</strong><br>';
|
|
// Para demo, solo muestra las respuestas seleccionadas
|
|
preguntas.forEach((q, idx) => {
|
|
const inputs = quizSection.querySelectorAll(`[name="q${idx}"]:checked`);
|
|
const seleccionadas = Array.from(inputs).map(i => i.value);
|
|
resultado += `Pregunta ${idx + 1}: Seleccionaste: ${seleccionadas.join(', ') || 'Ninguna'}<br>`;
|
|
});
|
|
resultado += '</div>';
|
|
quizSection.innerHTML += resultado;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|