feat(WP-0014): Aufgaben-Phasenzuordnung und Fertigstellungs-Scores
Aufgabe bekommt ein phase-Feld (1–8). aufgaben_score()-Helper in core/services.py berechnet abgeschlossen/total/score_pct für jedes QuerySet. Score-Spalten in Ausschreibungen-Liste, Lose-Liste und Ausschreibungs-Detail; per-Phase-Scores in der Seitenleisten-Navigation. Phasenfilter in Aufgaben-Liste. 68 Tests grün. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f5950b6cbc
commit
e4eb5bc368
14 changed files with 343 additions and 5 deletions
|
|
@ -32,6 +32,15 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Phase</label>
|
||||
<select name="phase" class="form-input text-xs">
|
||||
<option value="">Alle Phasen</option>
|
||||
{% for val, label in phase_choices %}
|
||||
<option value="{{ val }}"{% if current_phase == val|stringformat:"s" %} selected{% endif %}>{{ val }}. {{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Verantwortlich</label>
|
||||
<select name="verantwortlicher" class="form-input text-xs">
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<p class="text-sm text-slate-500 mt-0.5">{{ ausschreibung.ausschreiber }}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
{% with s=aufgaben_score %}{% if s.total %}<span class="text-xs text-slate-500">Aufgaben: {{ s.abgeschlossen }}/{{ s.total }} ({{ s.score_pct }} %)</span>{% endif %}{% endwith %}
|
||||
{% include "ausschreibungen/partials/status_widget.html" %}
|
||||
<a href="{% url 'ausschreibungen:bearbeiten' ausschreibung.pk %}" class="btn-ghost text-xs">Bearbeiten</a>
|
||||
<a href="{% url 'ausschreibungen:archivieren' ausschreibung.pk %}" class="btn-ghost text-xs text-slate-400">Archivieren</a>
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
{% render_field ausschreibung "ausschreiber" "Ausschreiber" %}
|
||||
{% render_field ausschreibung "vergabeart" "Vergabeart" %}
|
||||
{% render_field ausschreibung "rechtsgrundlage" "Rechtsgrundlage" %}
|
||||
{% render_field ausschreibung "rechtsgrundlage_details" "Rechtsgrundlage Details" %}
|
||||
{% render_field ausschreibung "vergabenummer" "Vergabenummer" %}
|
||||
{% render_field ausschreibung "vergabeplattform" "Plattform" %}
|
||||
{% render_field ausschreibung "branche" "Branche" %}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
<th class="text-left px-4 py-2 font-medium text-slate-600">Ausschreiber</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Titel</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Volumen (gesch.)</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Aufgaben</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Status</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Abgabe</th>
|
||||
<th class="text-left px-4 py-2 font-medium text-slate-600">Bid Manager</th>
|
||||
|
|
@ -24,6 +25,12 @@
|
|||
<td class="px-4 py-2 text-slate-600 text-right whitespace-nowrap">
|
||||
{% if a.geschaetztes_volumen %}{{ a.geschaetztes_volumen|floatformat:0 }} €{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-2 text-slate-600 whitespace-nowrap">
|
||||
{% if a.aufgaben_total %}
|
||||
{{ a.aufgaben_erledigt }}/{{ a.aufgaben_total }}
|
||||
({% widthratio a.aufgaben_erledigt a.aufgaben_total 100 %} %)
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-2">
|
||||
{% status_badge a.status a.get_status_display %}
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
<th class="pb-2 pr-4">Nr.</th>
|
||||
<th class="pb-2 pr-4">Titel</th>
|
||||
<th class="pb-2 pr-4">Zuständig</th>
|
||||
<th class="pb-2 pr-4">Aufgaben</th>
|
||||
<th class="pb-2 pr-4">Teilnahme</th>
|
||||
<th class="pb-2"></th>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
class="text-brand-600 hover:underline font-medium">{{ los.lostitel }}</a>
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-slate-600">{{ los.zustaendiger|default:"—" }}</td>
|
||||
<td class="py-2 pr-4 text-slate-600 whitespace-nowrap">
|
||||
{% if los.aufgaben_total %}
|
||||
{{ los.aufgaben_erledigt }}/{{ los.aufgaben_total }}
|
||||
({% widthratio los.aufgaben_erledigt los.aufgaben_total 100 %} %)
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td class="py-2 pr-4">
|
||||
{% if los.teilnahme is None %}
|
||||
<span class="text-slate-400 text-xs">Offen</span>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
{{ phase.nummer }}
|
||||
</span>
|
||||
<span class="truncate">{{ phase.name }}</span>
|
||||
{% if phase.warnung %}
|
||||
{% if phase.aufgaben_score.total %}
|
||||
<span class="ml-auto text-slate-400 text-xs shrink-0">{{ phase.aufgaben_score.abgeschlossen }}/{{ phase.aufgaben_score.total }}</span>
|
||||
{% elif phase.warnung %}
|
||||
<span class="ml-auto text-amber-500 text-xs shrink-0">⚠</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue