diff --git a/ticketsystem/forms.py b/ticketsystem/forms.py index 6b38809..d4f43cd 100644 --- a/ticketsystem/forms.py +++ b/ticketsystem/forms.py @@ -1,5 +1,6 @@ from django import forms from .models import Comment, Ticket +from django.core.exceptions import ValidationError class CommentForm(forms.ModelForm): @@ -16,7 +17,26 @@ class CommentForm(forms.ModelForm): class TicketForm(forms.ModelForm): class Meta: model = Ticket - fields = ["title", "description", "status", "priority", "course"] + fields = ["title", "description", "status", "priority", "course", "answer"] + widgets = { + 'answer': forms.Textarea(attrs={ + 'rows': 4, + 'placeholder': 'Beschreibe die Lösung des Problems...' + }) + } + + def clean(self): + cleaned_data = super().clean() + status = cleaned_data.get('status') + answer = cleaned_data.get('answer') + + # Wenn Status auf "gelöst" gesetzt wird, muss eine Antwort vorhanden sein + if status == 'resolved' and not answer: + raise ValidationError({ + 'answer': 'Eine Antwort ist erforderlich, wenn der Status auf "Gelöst" gesetzt wird.' + }) + + return cleaned_data def save(self, commit=True): ticket = super().save(commit=False) @@ -25,6 +45,11 @@ class TicketForm(forms.ModelForm): if ticket.course and ticket.course.tutor: ticket.assigned_to = ticket.course.tutor + # Setze answered_at wenn eine Antwort gegeben wird + if ticket.answer and not ticket.answered_at: + from django.utils import timezone + ticket.answered_at = timezone.now() + if commit: ticket.save() return ticket \ No newline at end of file diff --git a/ticketsystem/models.py b/ticketsystem/models.py index b982d60..7c8a191 100644 --- a/ticketsystem/models.py +++ b/ticketsystem/models.py @@ -51,6 +51,18 @@ class Ticket(models.Model): status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="new") priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default="medium") + answer = models.TextField( + blank=True, + null=True, + verbose_name="Antwort/Lösung", + help_text="Beschreibung der Lösung (erforderlich bei Status 'Gelöst')" + ) + answered_at = models.DateTimeField( + blank=True, + null=True, + verbose_name="Beantwortet am" + ) + course = models.ForeignKey( Course, on_delete=models.CASCADE, diff --git a/ticketsystem/templates/ticketsystem/base.html b/ticketsystem/templates/ticketsystem/base.html index ee1eb7e..6c9da6d 100644 --- a/ticketsystem/templates/ticketsystem/base.html +++ b/ticketsystem/templates/ticketsystem/base.html @@ -30,7 +30,7 @@ -
+
{% block content %}{% endblock %}
diff --git a/ticketsystem/templates/ticketsystem/detail.html b/ticketsystem/templates/ticketsystem/detail.html index e3e264b..1ce768c 100644 --- a/ticketsystem/templates/ticketsystem/detail.html +++ b/ticketsystem/templates/ticketsystem/detail.html @@ -2,7 +2,7 @@ {% block content %} {% if messages %} -
+
{% for message in messages %}
{{ message }} @@ -10,7 +10,7 @@ {% endfor %}
{% endif %} -
+

🎫 Ticket #{{ ticket.id }} – {{ ticket.title }}

@@ -71,13 +71,50 @@
+
-
+
{% if ticket.assigned_to %}{{ ticket.assigned_to.username }}{% else %}Niemand zugewiesen{% endif %}

Wird automatisch basierend auf dem ausgewählten Kurs zugewiesen

+ + +
+ + {% if ticket.answer and not view.can_edit %} + +
+
{{ ticket.answer|linebreaks }}
+ {% if ticket.answered_at %} +
+ Beantwortet am: {{ ticket.answered_at|date:"d.m.Y H:i" }} +
+ {% endif %} +
+ {% else %} + + + {% if form.answer.errors %} +
{{ form.answer.errors }}
+ {% endif %} +

+ {% if ticket.status != 'resolved' %} + Eine Antwort ist erforderlich beim Setzen des Status auf "Gelöst" + {% endif %} +

+ {% endif %} +
{% if view.can_edit %} @@ -178,5 +215,40 @@ }); {% endif %} }); + + // Answer Feld nur bei Status "resolved" aktivieren + {% if view.can_edit %} + document.addEventListener('DOMContentLoaded', function() { + const statusSelect = document.querySelector('select[name="status"]'); + const answerField = document.querySelector('textarea[name="answer"]'); + const answerLabel = answerField.previousElementSibling; + + function toggleAnswerField() { + if (statusSelect.value === 'resolved') { + answerField.disabled = false; + answerField.classList.remove('bg-gray-100', 'cursor-not-allowed'); + answerField.classList.add('bg-white'); + answerField.required = true; + // Pflichtfeld-Stern anzeigen + if (!answerLabel.querySelector('.text-red-500')) { + answerLabel.innerHTML = answerLabel.textContent + ' *'; + } + } else { + answerField.disabled = true; + answerField.classList.add('bg-gray-100', 'cursor-not-allowed'); + answerField.classList.remove('bg-white'); + answerField.required = false; + // Pflichtfeld-Stern entfernen + answerLabel.innerHTML = answerLabel.textContent.replace(' *', ''); + } + } + + // Initial prüfen + toggleAnswerField(); + + // Bei Status-Änderung prüfen + statusSelect.addEventListener('change', toggleAnswerField); + }); + {% endif %} {% endblock %} \ No newline at end of file diff --git a/ticketsystem/templates/ticketsystem/faq.html b/ticketsystem/templates/ticketsystem/faq.html index 086784b..736139b 100644 --- a/ticketsystem/templates/ticketsystem/faq.html +++ b/ticketsystem/templates/ticketsystem/faq.html @@ -1,6 +1,6 @@ {% extends "ticketsystem/base.html" %} {% block content %} -
+
diff --git a/ticketsystem/templates/ticketsystem/home.html b/ticketsystem/templates/ticketsystem/home.html index 2cb6e89..a750244 100644 --- a/ticketsystem/templates/ticketsystem/home.html +++ b/ticketsystem/templates/ticketsystem/home.html @@ -1,6 +1,6 @@ {% extends "ticketsystem/base.html" %} {% block content %} -
+
🎫
diff --git a/ticketsystem/templates/ticketsystem/ticket_form.html b/ticketsystem/templates/ticketsystem/ticket_form.html index de1b967..adff900 100644 --- a/ticketsystem/templates/ticketsystem/ticket_form.html +++ b/ticketsystem/templates/ticketsystem/ticket_form.html @@ -2,7 +2,7 @@ {% block content %} {% if messages %} -
+
{% for message in messages %}
{{ message }} @@ -10,7 +10,7 @@ {% endfor %}
{% endif %} -
+

➕ Neues Ticket erstellen

diff --git a/ticketsystem/views.py b/ticketsystem/views.py index 58227eb..e62fa19 100644 --- a/ticketsystem/views.py +++ b/ticketsystem/views.py @@ -107,7 +107,7 @@ class TicketDetailUpdateView(UpdateView): response = super().form_valid(form) # Speichert das Ticket # History tracking für geänderte Felder - tracked_fields = ["title", "description", "status", "priority", "course"] + tracked_fields = ["title", "description", "status", "priority", "course", "answer"] for field in tracked_fields: if field in form.changed_data: old_value = getattr(original, field) @@ -123,6 +123,15 @@ class TicketDetailUpdateView(UpdateView): elif field == "course": old_value = str(old_value) new_value = str(new_value) + elif field == "answer": + if old_value: + old_value = old_value[:50] + "..." if len(old_value) > 50 else old_value + else: + old_value = "Keine Antwort" + if new_value: + new_value = new_value[:50] + "..." if len(new_value) > 50 else new_value + else: + new_value = "Keine Antwort" TicketHistory.objects.create( ticket=ticket,