Compare commits
3 commits
f96c24a474
...
d9756d5f60
Author | SHA1 | Date | |
---|---|---|---|
d9756d5f60 | |||
39da362586 | |||
57b7c6372d |
6 changed files with 147 additions and 11 deletions
|
@ -1255,3 +1255,8 @@ div.gdpr {
|
||||||
label[for=id_skola] {
|
label[for=id_skola] {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* detail řešení */
|
||||||
|
.bodovani>input {
|
||||||
|
width: 4em;
|
||||||
|
}
|
||||||
|
|
|
@ -103,6 +103,22 @@ class JednoHodnoceniForm(forms.ModelForm):
|
||||||
'feedback': forms.Textarea(attrs={'rows': 1, 'cols': 30, 'class': 'feedback'}),
|
'feedback': forms.Textarea(attrs={'rows': 1, 'cols': 30, 'class': 'feedback'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body_celkem = forms.DecimalField(required=False, decimal_places=1)
|
||||||
|
body_neprepocitane = forms.DecimalField(required=False, decimal_places=1)
|
||||||
|
body_neprepocitane_celkem = forms.DecimalField(required=False, decimal_places=1)
|
||||||
|
|
||||||
|
def __init__(self, *args, initial=None, **kwargs):
|
||||||
|
if initial is not None:
|
||||||
|
body_max = initial["body_max"]
|
||||||
|
body_neprepocitane_max = initial["body_neprepocitane_max"]
|
||||||
|
del(initial["body_max"])
|
||||||
|
del(initial["body_neprepocitane_max"])
|
||||||
|
super().__init__(*args, initial=initial, **kwargs)
|
||||||
|
if initial is not None:
|
||||||
|
self.fields['body_celkem'].widget.attrs['placeholder'] = body_max
|
||||||
|
self.fields['body_neprepocitane_celkem'].widget.attrs['placeholder'] = body_neprepocitane_max
|
||||||
|
|
||||||
|
|
||||||
OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm,
|
OhodnoceniReseniFormSet = formset_factory(JednoHodnoceniForm,
|
||||||
extra = 0,
|
extra = 0,
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,8 +49,18 @@ $(document).ready(function(){
|
||||||
$('#id_form-' + form_idx + '-deadline_body')[0].value = $('#id_form-' + (form_idx - 1) + '-deadline_body')[0].value
|
$('#id_form-' + form_idx + '-deadline_body')[0].value = $('#id_form-' + (form_idx - 1) + '-deadline_body')[0].value
|
||||||
}
|
}
|
||||||
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
|
|
||||||
|
$('.bodovani').children().change(function(){
|
||||||
|
$(this).parent().parent().children(".bodovani").children().attr("disabled", true);
|
||||||
|
$(this).attr("disabled", false);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
$('.smazat_hodnoceni').click(function(){
|
$('.smazat_hodnoceni').click(function(){
|
||||||
deleteForm("form",this);
|
deleteForm("form",this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.bodovani').children().change(function(){
|
||||||
|
$(this).parent().parent().children(".bodovani").children().attr("disabled", true);
|
||||||
|
$(this).attr("disabled", false);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,12 +54,15 @@
|
||||||
{{ form.management_form }}
|
{{ form.management_form }}
|
||||||
</table>
|
</table>
|
||||||
<table id="form_set">
|
<table id="form_set">
|
||||||
<tr><th>Problém</th><th>Body</th><th>Deadline pro body</th><th>Zpětná vazba pro řešitele</th></tr>
|
<tr><th>Problém</th><th>{# 📖 #}🧍</th><th>{# 🔵 #}🧍∑</th><th>{# 💪 #}🧑🤝🧑</th><th>{# ❤ #}🧑🤝🧑∑</th><th>Deadline pro body</th><th>Zpětná vazba pro řešitele</th></tr>
|
||||||
{% for subform in form %}
|
{% for subform in form %}
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="hodnoceni">
|
<tr class="hodnoceni">
|
||||||
<td>{{ subform.problem }}</td>
|
<td>{{ subform.problem }}</td>
|
||||||
<td>{{ subform.body }}</td>
|
<td class="bodovani">{{ subform.body }}</td>
|
||||||
|
<td class="bodovani">{{ subform.body_celkem }}</td>
|
||||||
|
<td class="bodovani">{{ subform.body_neprepocitane }}</td>
|
||||||
|
<td class="bodovani">{{ subform.body_neprepocitane_celkem }}</td>
|
||||||
<td>{{ subform.deadline_body }}</td>
|
<td>{{ subform.deadline_body }}</td>
|
||||||
<td>{{ subform.feedback }}</td>
|
<td>{{ subform.feedback }}</td>
|
||||||
<td class="has_smazat_hodnoceni"><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove" title="Smazat hodnocení"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td>
|
<td class="has_smazat_hodnoceni"><a href="#" class="smazat_hodnoceni" id="id_{{subform.prefix}}-jsremove" title="Smazat hodnocení"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td>
|
||||||
|
@ -72,10 +75,15 @@
|
||||||
<a href="#" title="Přidat hodnocení"> <img src="{% static "odevzdavatko/plus.png" %}" id="pridat_hodnoceni" alt="Přidat hodnocení"></a> <br/>
|
<a href="#" title="Přidat hodnocení"> <img src="{% static "odevzdavatko/plus.png" %}" id="pridat_hodnoceni" alt="Přidat hodnocení"></a> <br/>
|
||||||
<input type=submit value="Uložit"></form>
|
<input type=submit value="Uložit"></form>
|
||||||
|
|
||||||
|
{# FIXME Zablokovat ostatni při změně #}
|
||||||
|
|
||||||
<table id="empty_form" style="display: none;">
|
<table id="empty_form" style="display: none;">
|
||||||
<tr class="hodnoceni">
|
<tr class="hodnoceni">
|
||||||
<td>{{ form.empty_form.problem }}</td>
|
<td>{{ form.empty_form.problem }}</td>
|
||||||
<td>{{ form.empty_form.body }}</td>
|
<td class="bodovani">{{ form.empty_form.body }}</td>
|
||||||
|
<td class="bodovani">{{ form.empty_form.body_celkem }}</td>
|
||||||
|
<td class="bodovani">{{ form.empty_form.body_neprepocitane }}</td>
|
||||||
|
<td class="bodovani">{{ form.empty_form.body_neprepocitane_celkem }}</td>
|
||||||
<td>{{ form.empty_form.deadline_body }}</td>
|
<td>{{ form.empty_form.deadline_body }}</td>
|
||||||
<td>{{ form.empty_form.feedback }}</td>
|
<td>{{ form.empty_form.feedback }}</td>
|
||||||
<td class="has_smazat_hodnoceni"><a href="#" class="smazat_hodnoceni" id="id_{{form.empty_form.prefix}}-jsremove" title="Smazat hodnocení"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td>
|
<td class="has_smazat_hodnoceni"><a href="#" class="smazat_hodnoceni" id="id_{{form.empty_form.prefix}}-jsremove" title="Smazat hodnocení"><img src="{% static "odevzdavatko/cross.png" %}" alt="Smazat"></a></td>
|
||||||
|
@ -85,16 +93,33 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<h3>Hodnocení:</h3>
|
<h3>Hodnocení:</h3>
|
||||||
<table class="dosla_reseni">
|
<table class="dosla_reseni">
|
||||||
<tr><th>Problém</th><th>Body</th><th>Zpětná vazba od opravovatele</th></tr>
|
<tr><th>Problém</th><th>{# 📖 #}🧍</th><th>{# 🔵 #}🧍∑</th><th>{# 💪 #}🧑🤝🧑</th><th>{# ❤ #}🧑🤝🧑∑</th><th>Zpětná vazba od opravovatele</th></tr>
|
||||||
{% for h in hodnoceni %}
|
{% for h in hodnoceni %}
|
||||||
<tr class="hodnoceni">
|
<tr class="hodnoceni">
|
||||||
<td>{{ h.problem }}</td>
|
<td>{{ h.problem }}</td>
|
||||||
<td>{{ h.body }}</td>
|
<td class="bodovani">{{ h.body }}</td>
|
||||||
|
<td class="bodovani">{{ h.body_celkem }}</td>
|
||||||
|
<td class="bodovani">{{ h.body_neprepocitane }}</td>
|
||||||
|
<td class="bodovani">{{ h.body_neprepocitane_celkem }}</td>
|
||||||
<td>{{ h.feedback }}</td>
|
<td>{{ h.feedback }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>{# 📖 #}🧍</dt>
|
||||||
|
<dd>Body, které dostává jeden řešitel za toto řešení.</dd>
|
||||||
|
|
||||||
|
<dt>{# 🔵 #}🧍∑</dt>
|
||||||
|
<dd>Body, které dostává jeden řešitel za tento problém (součet za všechna řešení).</dd>
|
||||||
|
|
||||||
|
<dt>{# 💪 #}🧑🤝🧑</dt>
|
||||||
|
<dd>Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za toto řešení.</dd>
|
||||||
|
|
||||||
|
<dt>{# ❤ #}🧑🤝🧑∑</dt>
|
||||||
|
<dd>Body, které by dostal tým, kdyby to řešil jako jeden řešitel, za tento problém (součet za všechna řešení).</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -224,12 +224,18 @@ class DetailReseniView(DetailView):
|
||||||
self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk'])
|
self.reseni = get_object_or_404(m.Reseni, id=self.kwargs['pk'])
|
||||||
result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet
|
result = [] # Slovníky s klíči problem, body, deadline_body -- initial data pro f.OhodnoceniReseniFormSet
|
||||||
for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni):
|
for hodn in m.Hodnoceni.objects.filter(reseni=self.reseni):
|
||||||
result.append({
|
seznam_atributu = [
|
||||||
"problem": hodn.problem,
|
"problem",
|
||||||
"body": hodn.body,
|
"body",
|
||||||
"deadline_body": hodn.deadline_body,
|
"body_celkem",
|
||||||
"feedback": hodn.feedback,
|
"body_neprepocitane",
|
||||||
})
|
"body_neprepocitane_celkem",
|
||||||
|
"body_max",
|
||||||
|
"body_neprepocitane_max",
|
||||||
|
"deadline_body",
|
||||||
|
"feedback",
|
||||||
|
]
|
||||||
|
result.append({attr: getattr(hodn, attr) for attr in seznam_atributu})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_context_data(self, **kw):
|
def get_context_data(self, **kw):
|
||||||
|
@ -292,11 +298,20 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
|
||||||
|
|
||||||
# Vyrobíme nová podle formsetu
|
# Vyrobíme nová podle formsetu
|
||||||
for form in formset:
|
for form in formset:
|
||||||
|
data_for_hodnoceni = form.cleaned_data
|
||||||
|
data_for_body = data_for_hodnoceni.copy()
|
||||||
|
del(data_for_hodnoceni["body_celkem"])
|
||||||
|
del(data_for_hodnoceni["body_neprepocitane"])
|
||||||
|
del(data_for_hodnoceni["body_neprepocitane_celkem"])
|
||||||
hodnoceni = m.Hodnoceni(
|
hodnoceni = m.Hodnoceni(
|
||||||
reseni=reseni,
|
reseni=reseni,
|
||||||
**form.cleaned_data,
|
**form.cleaned_data,
|
||||||
)
|
)
|
||||||
logger.info(f"Creating Hodnoceni: {hodnoceni}")
|
logger.info(f"Creating Hodnoceni: {hodnoceni}")
|
||||||
|
zmeny_bodu = [it for it in form.changed_data if it.startswith("body")]
|
||||||
|
if len(zmeny_bodu) == 1:
|
||||||
|
hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]])
|
||||||
|
hodnoceni.save()
|
||||||
hodnoceni.save()
|
hodnoceni.save()
|
||||||
|
|
||||||
return redirect(success_url)
|
return redirect(success_url)
|
||||||
|
|
|
@ -115,6 +115,71 @@ class Hodnoceni(bm.SeminarModelBase):
|
||||||
|
|
||||||
feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)')
|
feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)')
|
||||||
|
|
||||||
|
# TODO najít správné místo
|
||||||
|
@staticmethod
|
||||||
|
def vzorecek_na_prepocet(body, resitelu):
|
||||||
|
return body * 3 / (resitelu + 2)
|
||||||
|
|
||||||
|
# TODO najít správné místo
|
||||||
|
@staticmethod
|
||||||
|
def inverze_vzorecku_na_prepocet(body, resitelu):
|
||||||
|
return body * (resitelu + 2) / 3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_celkem(self):
|
||||||
|
# FIXME řeším jen prvního řešitele.
|
||||||
|
return Hodnoceni.objects.filter(problem=self.problem, reseni__resitele=self.reseni.resitele.first(), body__isnull=False).aggregate(Sum("body"))["body__sum"]
|
||||||
|
|
||||||
|
@body_celkem.setter
|
||||||
|
def body_celkem(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
if self.body is None:
|
||||||
|
self.body = 0
|
||||||
|
if self.body_celkem is None:
|
||||||
|
self.body += value
|
||||||
|
else:
|
||||||
|
self.body += value - self.body_celkem
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane(self):
|
||||||
|
if self.body is None:
|
||||||
|
return None
|
||||||
|
return self.inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@body_neprepocitane.setter
|
||||||
|
def body_neprepocitane(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
self.body = self.vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane_celkem(self):
|
||||||
|
if self.body_celkem is None:
|
||||||
|
return None
|
||||||
|
return self.inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@body_neprepocitane_celkem.setter
|
||||||
|
def body_neprepocitane_celkem(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
self.body_celkem = self.vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_max(self):
|
||||||
|
if not isinstance(Hodnoceni.objects.first().problem, am.Uloha):
|
||||||
|
return None
|
||||||
|
return self.problem.uloha.max_body
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane_max(self):
|
||||||
|
if self.body_max is None:
|
||||||
|
return None
|
||||||
|
return self.inverze_vzorecku_na_prepocet(self.body_max, self.reseni.resitele.count())
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
|
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue