Eingabe_Funktion

This commit is contained in:
ben8
2025-05-02 17:06:29 +02:00
parent a7c42ecf13
commit a6cac52ba6
7 changed files with 245 additions and 18 deletions

View File

@@ -359,7 +359,7 @@ def new_question(request):
messages.error(request, 'Quiz nicht gefunden oder keine Berechtigung.')
return redirect('library:overview_quiz')
if question_type not in ['multiple_choice', 'true_false']:
if question_type not in ['multiple_choice', 'true_false','input']:
base_url = reverse('library:new_question')
return redirect(f'{base_url}?type=multiple_choice&quiz_id={quiz_id}')
@@ -377,6 +377,17 @@ def new_question(request):
{'value': 'Falsch', 'is_correct': not correct_answer}
]
}
elif question_type == 'input':
correct_answer = request.POST.get('correct_answer')
json_data = {
'type': question_type,
'question': question_text,
'options': [
{'value': correct_answer, 'is_correct': True}
]
}
elif question_type == 'multiple_choice':
options = []
i = 1
@@ -428,6 +439,18 @@ def new_question(request):
]
}
standard_time_per_question = 30
elif question_type == 'input':
question_data = {
'type': question_type,
'question': '',
'options': [
]
}
standard_time_per_question = 30
elif question_type == 'multiple_choice':
question_data = {
'type': question_type,
@@ -525,6 +548,17 @@ def edit_question(request, pk):
{'value': 'Falsch', 'is_correct': not correct_answer}
]
}
elif question_type == 'input':
correct_answer = request.POST.get('correct_answer')
json_data = {
'type': question_type,
'question': question_text,
'options': [
{'value': correct_answer,'is_correct':True}
]
}
elif question_type == 'multiple_choice':
options = []
i = 1

View File

@@ -84,7 +84,10 @@ class GameConsumer(AsyncWebsocketConsumer):
elif message_type == 'submit_answer':
participant_id = text_data_json['participant_id']
answer = text_data_json['answer']
try:
answer = text_data_json['answer']
except:
answer=-1
time_remaining = text_data_json.get('time_remaining', 0)
# Save answer and update participant score
@@ -182,15 +185,30 @@ class GameConsumer(AsyncWebsocketConsumer):
# Check if answer is correct
is_correct = False
if answer_index >= 0: # -1 means timeout
question_data = json.loads(current_question.data)
question_data = json.loads(current_question.data)
print(answer_index)
try:
#if answer_index >= 0 : # -1 means timeout
is_correct = question_data['options'][answer_index]['is_correct']
print(is_correct)
except:
user_input = str(answer_index).strip().lower()
correct_value = str(question_data['options'][0].get('value', '')).strip().lower()
print("Richtig",correct_value)
if user_input == correct_value:
is_correct=True
answer_index=0
print(is_correct)
# Calculate score based on correctness and time
score = 0
if is_correct:
base_score = 1000
time_factor = time_remaining / 30000 # 30 seconds max
time_factor = time_remaining / int(current_question.time_per_question)/int(1000)
score = int(base_score * (0.5 + 0.5 * time_factor))
# Update or create answer in QuizAnswer table

View File

@@ -90,6 +90,14 @@
<div class="flex justify-between items-center flex-wrap">
<h2 class="text-xl font-semibold">Fragen</h2>
<div class="flex space-x-2 flex-wrap">
{% if quiz.user_id == request.user %}
<a href="{% url 'library:new_question' %}?type=input&quiz_id={{ quiz.id }}"
class=" mt-1 bg-green-100 text-green-800 px-4 py-2 rounded-md text-xs lg:text-lg hover:border-blue-600 border-2">
Eingabe
</a>
{% endif %}
{% if quiz.user_id == request.user %}
<a href="{% url 'library:new_question' %}?type=multiple_choice&quiz_id={{ quiz.id }}"
class=" mt-1 bg-blue-100 text-blue-800 px-4 py-2 rounded-md text-xs lg:text-lg hover:border-blue-600 border-2">
@@ -118,8 +126,8 @@
<div class="flex-grow">
<p class="font-medium">{{ question.data.question }}</p>
<div class="mt-1">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {% if question.data.type == 'multiple_choice' %}bg-blue-100 text-blue-800{% else %}bg-purple-100 text-purple-800{% endif %}">
{% if question.data.type == 'multiple_choice' %}Multiple Choice{% else %}Wahr/Falsch{% endif %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {% if question.data.type == 'multiple_choice' %}bg-blue-100 text-blue-800 {% elif question.data.type == 'input' %} bg-green-100 text-green-800 {% else %}bg-purple-100 text-purple-800{% endif %}">
{% if question.data.type == 'multiple_choice' %}Multiple Choice{% elif question.data.type == 'input' %}Eingabe{% else %}Wahr/Falsch{% endif %}
</span>
</div>
<div class="mt-2">
@@ -143,6 +151,18 @@
</li>
{% endfor %}
</ul>
{% elif question.data.type == 'input' %}
<ul class="space-y-1 ">
{% for option in question.data.options %}
<li class="flex items-center text-sm">
<svg class="h-4 w-4 text-green-500 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
<span class="font-medium text-green-700">{{ option.value }}</span>
</li>
{% endfor %}
</ul>
{% else %}
{% for option in question.data.options %}
{% if option.is_correct %}

View File

@@ -0,0 +1,93 @@
{% extends 'base.html' %}
{% block content %}
<div class="container mx-auto px-4">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold">{% if question %}Frage bearbeiten{% else %}Neue Eingabe Frage{% endif %}</h1>
<a href="{% url 'library:detail_quiz' quiz.id %}"
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
Zurück zum Quiz
</a>
</div>
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
<form method="post" class="space-y-6" enctype="multipart/form-data">
{% csrf_token %}
<!-- Question Text -->
<div>
<label for="question" class="block text-sm font-medium text-gray-700">Frage</label>
<div class="mt-1">
<textarea name="question" id="question" rows="4"
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
required>{{ question.data.question }}</textarea>
</div>
</div>
{% if image %}
<img src="{{ image.image.url }}" style="max-width: 500px;" alt="Bild der Frage">
<label for="reset_image">
<input type="checkbox" name="reset_ques_image" id="reset_ques_image">
Bild zurücksetzen
</label>
{% endif %}
<div>
<label class="font-bold" for="question_image">Bild:</label>
<input class="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="question_image" id="question_image">
</div>
<!-- Eingabe -->
{% if question and question.data.options %}
{% for option in question.data.options %}
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
<div class="flex space-x-4">
<textarea name="correct_answer" rows="2"
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
required>{{ option.value }}</textarea>
</div>
</div>
{% endfor %}
{% else %}
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
<div class="flex space-x-4">
<textarea name="correct_answer" rows="2"
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
required></textarea>
</div>
</div>
{% endif %}
<div class="p-4">
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
<select name="time_per_question" id="time_per_question">
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
<option value="45" {% if standard_time_per_question == "45" or time_per_question == "45" %}selected{% endif %}>45 Sekunden</option>
<option value="60" {% if standard_time_per_question == "60" or time_per_question == "60" %}selected{% endif %}>1 Minute</option>
<option value="120" {% if standard_time_per_question == "120" or time_per_question == "120" %}selected{% endif %}>2 Minuten</option>
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
</select>
</div>
<div class="flex justify-end space-x-3">
<a href="{% url 'library:detail_quiz' quiz.id %}"
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
Abbrechen
</a>
<button type="submit"
class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
{% if question %}Speichern{% else %}Erstellen{% endif %}
</button>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@@ -36,7 +36,7 @@
<p id="answer-count" class="text-6xl font-bold text-blue-700">0/0</p>
</div>
</div>
{% if question_data.type != "input" %}
<div class="grid grid-cols-2 gap-4" id="options-container">
{% for option in question_data.options %}
<button
@@ -48,7 +48,20 @@
</button>
{% endfor %}
</div>
{% else %}
{% if request.session.mode == "learn" %}
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
<button {% if request.session.mode == "learn" %}
onclick="submitAnswer( -1 );" {% endif %}
class="text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
abschicken
</button>
{% endif %}
{% endif %}
</div>
@@ -155,7 +168,9 @@
gameSocket.send(JSON.stringify({
'type': 'update_participants'
}));
{% if request.session.mode != "learn" %}
updateTimer();
{% endif %}
};
@@ -177,10 +192,20 @@
function submitAnswer(optionIndex) {
if (hasAnswered) return;
let input = ""; // Declare input here
try {
input = document.getElementById("textanswer").value;
} catch (e) {
input = "";
}
hasAnswered = true;
const now = Date.now();
const timeRemaining = Math.max(0, questionDuration - (now - questionStartTime));
let timeRemaining = Math.max(0, questionDuration - (now - questionStartTime));
{% if request.session.mode == "learn" %}
timeRemaining = questionDuration;
{% endif %}
// Disable all options and highlight selected
const options = document.getElementsByClassName('answer-option');
@@ -194,14 +219,23 @@
option.classList.add('opacity-50');
}
}
if(input!=""){
// Send answer to server
gameSocket.send(JSON.stringify({
type: 'submit_answer',
participant_id: participantId,
answer: optionIndex,
answer:input,
time_remaining: timeRemaining
}));
}
else{
gameSocket.send(JSON.stringify({
type: 'submit_answer',
participant_id: participantId,
answer:optionIndex,
time_remaining: timeRemaining
}));
}
}
</script>
{% endblock %}

View File

@@ -15,7 +15,7 @@
<p class="text-blue-600 text-xl mb-2">Verbleibende Zeit</p>
<p id="remaining-time" class="text-6xl font-bold text-blue-700">30</p>
</div>
{% if question_data.type != "input" %}
<div class="grid grid-cols-2 gap-4" id="options-container">
{% for option in question_data.options %}
<button
@@ -26,6 +26,15 @@
</button>
{% endfor %}
</div>
{% else %}
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
<button
onclick="submitAnswer( -1 );"
class="text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
abschicken
</button>
{% endif %}
</div>
</div>
{% endblock %}
@@ -57,6 +66,13 @@
function submitAnswer(optionIndex) {
if (hasAnswered) return;
let input = ""; // Declare input here
try {
input = document.getElementById("textanswer").value;
} catch (e) {
input = "";
}
hasAnswered = true;
const now = Date.now();
@@ -75,14 +91,26 @@
}
}
if(input!=""){
// Send answer to server
gameSocket.send(JSON.stringify({
type: 'submit_answer',
participant_id: participantId,
answer: optionIndex,
answer:input,
time_remaining: timeRemaining
}));
}
else{
gameSocket.send(JSON.stringify({
type: 'submit_answer',
participant_id: participantId,
answer:optionIndex,
time_remaining: timeRemaining
}));
}
}
// Timer
function updateTimer() {

View File

@@ -18,7 +18,7 @@
</div>
</div>
{% if request.session.mode != "learn" %}
<div class="mb-6">
<h2 class="text-xl font-bold mb-4">Punktestand</h2>
<div id="scoreboard" class="space-y-2">
@@ -48,7 +48,7 @@
{% endfor %}
</div>
</div>
{% endif %}
{% if is_host %}
{% if is_last_question %}
<button id="finish-button" class="w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">