We are building, workplan now registered with statehub
This commit is contained in:
parent
14b0bc6d01
commit
f202b71c75
37 changed files with 2036 additions and 22 deletions
93
vergabe_teilnahme/templates/lose/anforderung_detail.html
Normal file
93
vergabe_teilnahme/templates/lose/anforderung_detail.html
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
{% extends "base.html" %}
|
||||
{% load vergabe_tags %}
|
||||
{% block title %}{{ anforderung.titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div>
|
||||
<h1 class="page-title">{{ anforderung.titel }}</h1>
|
||||
<p class="text-sm text-slate-500 mt-0.5">
|
||||
{% if anforderung.los %}Los {{ anforderung.los.losnummer }}{% else %}Allgemein{% endif %}
|
||||
· {{ ausschreibung.titel }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2 shrink-0">
|
||||
{% include "lose/partials/erfuellungsstatus_widget.html" %}
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_bearbeiten' ausschreibung.pk anforderung.pk %}"
|
||||
class="btn-ghost text-xs">Bearbeiten</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if anforderung.ausschlusskriterium and anforderung.erfuellungsstatus == 'nicht_erfuellbar' %}
|
||||
<div class="bg-red-50 border border-red-300 rounded-lg px-4 py-3 mb-5">
|
||||
<p class="text-sm font-semibold text-red-700">⚠ Nicht erfüllbares Ausschlusskriterium</p>
|
||||
<p class="text-xs text-red-600 mt-1">Diese Anforderung gefährdet die Teilnahmemöglichkeit.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-3">Details</h2>
|
||||
<dl class="space-y-1">
|
||||
{% render_field anforderung "verbindlichkeit" "Verbindlichkeit" %}
|
||||
{% render_field anforderung "kategorie" "Kategorie" %}
|
||||
{% render_field anforderung "quelle_im_dokument" "Quelle im Dokument" %}
|
||||
{% render_field anforderung "zustaendiger" "Zuständiger" %}
|
||||
</dl>
|
||||
<div class="mt-3 flex gap-4 text-xs text-slate-600">
|
||||
{% if anforderung.ausschlusskriterium %}
|
||||
<span class="text-red-600 font-medium">Ausschlusskriterium</span>
|
||||
{% endif %}
|
||||
{% if anforderung.bewertungskriterium %}
|
||||
<span class="text-amber-700 font-medium">Bewertungskriterium</span>
|
||||
{% endif %}
|
||||
{% if anforderung.nachweis_erforderlich %}
|
||||
<span class="text-blue-700 font-medium">Nachweis erforderlich</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nachweise -->
|
||||
<div class="card">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Nachweise</h2>
|
||||
<button hx-get="{% url 'ausschreibungen:lose:nachweis_suche' ausschreibung.pk anforderung.pk %}"
|
||||
hx-target="#nachweis-modal"
|
||||
class="btn-ghost text-xs">Nachweis zuordnen</button>
|
||||
</div>
|
||||
<div id="nachweise-liste">
|
||||
{% include "lose/partials/nachweise_liste.html" %}
|
||||
</div>
|
||||
<div id="nachweis-modal"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if anforderung.beschreibung %}
|
||||
<div class="card mt-6">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-2">Beschreibung</h2>
|
||||
<p class="text-sm text-slate-600 whitespace-pre-line">{{ anforderung.beschreibung }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Verbundene Aufgaben -->
|
||||
<div class="card mt-6">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Verbundene Aufgaben ({{ aufgaben.count }})</h2>
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_aufgabe' ausschreibung.pk anforderung.pk %}"
|
||||
class="btn-ghost text-xs">+ Aufgabe erstellen</a>
|
||||
</div>
|
||||
{% if aufgaben %}
|
||||
<ul class="divide-y divide-slate-100 text-sm">
|
||||
{% for a in aufgaben %}
|
||||
<li class="py-2 flex items-center justify-between">
|
||||
<span>{{ a.titel }}</span>
|
||||
{% status_badge a.status a.get_status_display %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="text-sm text-slate-500">Keine Aufgaben verknüpft.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
93
vergabe_teilnahme/templates/lose/anforderung_form.html
Normal file
93
vergabe_teilnahme/templates/lose/anforderung_form.html
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}{{ titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1 class="page-title mb-6">{{ titel }}</h1>
|
||||
|
||||
<form method="post" class="max-w-2xl space-y-6">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card space-y-4">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Allgemein</h2>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Titel <span class="text-red-500">*</span></label>
|
||||
{{ form.titel }}
|
||||
{% if form.titel.errors %}<p class="text-xs text-red-600 mt-1">{{ form.titel.errors.0 }}</p>{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Beschreibung</label>
|
||||
{{ form.beschreibung }}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="form-label">Kategorie</label>
|
||||
{{ form.kategorie }}
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Los</label>
|
||||
{{ form.los }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quelle im Dokument</label>
|
||||
{{ form.quelle_im_dokument }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card space-y-4">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Verbindlichkeit & Bewertung</h2>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Verbindlichkeit <span class="text-red-500">*</span></label>
|
||||
<div class="flex gap-4 mt-1">
|
||||
{% for widget in form.verbindlichkeit %}
|
||||
<label class="flex items-center gap-1.5 text-sm cursor-pointer">
|
||||
{{ widget.tag }}
|
||||
<span>{{ widget.choice_label }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-6">
|
||||
<label class="flex items-center gap-2 text-sm cursor-pointer">
|
||||
{{ form.ausschlusskriterium }}
|
||||
<span>Ausschlusskriterium</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 text-sm cursor-pointer">
|
||||
{{ form.bewertungskriterium }}
|
||||
<span>Bewertungskriterium</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 text-sm cursor-pointer">
|
||||
{{ form.nachweis_erforderlich }}
|
||||
<span>Nachweis erforderlich</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="form-label">Erfüllungsstatus</label>
|
||||
{{ form.erfuellungsstatus }}
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Zuständiger</label>
|
||||
{{ form.zustaendiger }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="submit" class="btn-primary">Speichern</button>
|
||||
{% if anforderung %}
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_detail' ausschreibung.pk anforderung.pk %}" class="btn-ghost">Abbrechen</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ausschreibungen:lose:anforderungen_liste' ausschreibung.pk %}" class="btn-ghost">Abbrechen</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
51
vergabe_teilnahme/templates/lose/anforderungen_liste.html
Normal file
51
vergabe_teilnahme/templates/lose/anforderungen_liste.html
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{% extends "base.html" %}
|
||||
{% load vergabe_tags %}
|
||||
{% block title %}Anforderungen — {{ ausschreibung.titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="page-title">Anforderungen</h1>
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_neu' ausschreibung.pk %}" class="btn-primary text-xs">+ Anforderung</a>
|
||||
</div>
|
||||
|
||||
<!-- Filter -->
|
||||
<form id="filter-form" method="get"
|
||||
hx-get="{% url 'ausschreibungen:lose:anforderungen_liste' ausschreibung.pk %}"
|
||||
hx-target="#anforderungen-content"
|
||||
hx-trigger="change"
|
||||
class="card mb-5 flex flex-wrap gap-3 items-end">
|
||||
<div>
|
||||
<label class="form-label">Verbindlichkeit</label>
|
||||
<select name="verbindlichkeit" class="form-input text-xs h-8 w-auto">
|
||||
<option value="">Alle</option>
|
||||
{% for val, label in verbindlichkeit_choices %}
|
||||
<option value="{{ val }}" {% if val == current_verbindlichkeit %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Erfüllungsstatus</label>
|
||||
<select name="erfuellungsstatus" class="form-input text-xs h-8 w-auto">
|
||||
<option value="">Alle</option>
|
||||
{% for val, label in erfuellung_choices %}
|
||||
<option value="{{ val }}" {% if val == current_status %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Los</label>
|
||||
<select name="los" class="form-input text-xs h-8 w-auto">
|
||||
<option value="">Alle</option>
|
||||
<option value="allgemein" {% if current_los == 'allgemein' %}selected{% endif %}>Allgemein</option>
|
||||
{% for los in lose %}
|
||||
<option value="{{ los.pk }}" {% if current_los == los.pk|stringformat:"s" %}selected{% endif %}>Los {{ los.losnummer }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="anforderungen-content">
|
||||
{% include "lose/anforderungen_liste_partial.html" %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
{% load vergabe_tags %}
|
||||
{% if grouped %}
|
||||
{% for los, anforderungen in grouped.items %}
|
||||
<div x-data="{ open: true }" class="card mb-4">
|
||||
<button @click="open = !open"
|
||||
class="w-full flex items-center justify-between text-left">
|
||||
<h3 class="text-sm font-semibold text-slate-700">
|
||||
{% if los %}Los {{ los.losnummer }}: {{ los.lostitel }}{% else %}Allgemein{% endif %}
|
||||
<span class="text-slate-400 font-normal ml-1">({{ anforderungen|length }})</span>
|
||||
</h3>
|
||||
<span x-text="open ? '▲' : '▼'" class="text-xs text-slate-400"></span>
|
||||
</button>
|
||||
|
||||
<div x-show="open" class="mt-3">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-slate-200 text-left text-xs text-slate-500">
|
||||
<th class="pb-2 pr-4">Titel</th>
|
||||
<th class="pb-2 pr-4">Verbindlichkeit</th>
|
||||
<th class="pb-2 pr-4">Status</th>
|
||||
<th class="pb-2">Zuständig</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% for a in anforderungen %}
|
||||
<tr class="hover:bg-slate-50
|
||||
{% if a.ausschlusskriterium and a.erfuellungsstatus == 'nicht_erfuellbar' %}bg-red-50 border-l-2 border-red-400{% endif %}">
|
||||
<td class="py-2 pr-4">
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_detail' ausschreibung.pk a.pk %}"
|
||||
class="text-brand-600 hover:underline">{{ a.titel }}</a>
|
||||
{% if a.ausschlusskriterium %}
|
||||
<span class="ml-1 text-xs text-red-600 font-medium">⚠ AK</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="py-2 pr-4">{% status_badge a.verbindlichkeit a.get_verbindlichkeit_display %}</td>
|
||||
<td class="py-2 pr-4">{% status_badge a.erfuellungsstatus a.get_erfuellungsstatus_display %}</td>
|
||||
<td class="py-2 text-slate-500">{{ a.zustaendiger|default:"—" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="card text-center text-sm text-slate-500 py-8">
|
||||
Keine Anforderungen gefunden.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Aufgabe erstellen{% endblock %}
|
||||
{% block content %}
|
||||
<div class="max-w-md mx-auto mt-16">
|
||||
<div class="card space-y-4">
|
||||
<h1 class="text-lg font-semibold text-slate-800">Aufgabe aus Anforderung erstellen?</h1>
|
||||
<p class="text-sm text-slate-600">
|
||||
Eine neue Aufgabe vom Typ <strong>Fachlich</strong> wird erstellt:
|
||||
</p>
|
||||
<p class="text-sm font-medium text-slate-800 bg-slate-50 rounded p-3">
|
||||
Klärung: {{ anforderung.titel|truncatechars:200 }}
|
||||
</p>
|
||||
<form method="post" class="flex gap-3">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn-primary">Aufgabe erstellen</button>
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_detail' ausschreibung.pk anforderung.pk %}"
|
||||
class="btn-ghost">Abbrechen</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
89
vergabe_teilnahme/templates/lose/detail.html
Normal file
89
vergabe_teilnahme/templates/lose/detail.html
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
{% extends "base.html" %}
|
||||
{% load vergabe_tags %}
|
||||
{% block title %}{{ los }} — {{ ausschreibung.titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div>
|
||||
<h1 class="page-title">{{ los.lostitel }}</h1>
|
||||
<p class="text-sm text-slate-500 mt-0.5">Los {{ los.losnummer }} · {{ ausschreibung.titel }}</p>
|
||||
</div>
|
||||
<div class="flex gap-2 shrink-0">
|
||||
<a href="{% url 'ausschreibungen:lose:bearbeiten' ausschreibung.pk los.pk %}" class="btn-ghost text-xs">Bearbeiten</a>
|
||||
<a href="{% url 'ausschreibungen:lose:loeschen' ausschreibung.pk los.pk %}" class="btn-ghost text-xs text-slate-400">Löschen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-3">Stammdaten</h2>
|
||||
<dl class="space-y-1">
|
||||
{% render_field los "losnummer" "Losnummer" %}
|
||||
{% render_field los "lostitel" "Lostitel" %}
|
||||
{% render_field los "zustaendiger" "Zuständiger" %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-3">Teilnahme</h2>
|
||||
<p class="text-sm">
|
||||
{% if los.teilnahme is None %}
|
||||
<span class="text-slate-500">Noch nicht entschieden</span>
|
||||
{% elif los.teilnahme %}
|
||||
<span class="text-green-700 font-medium">Teilnahme</span>
|
||||
{% else %}
|
||||
<span class="text-red-700 font-medium">Keine Teilnahme</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if los.beschreibung %}
|
||||
<div class="card mt-6">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-2">Beschreibung</h2>
|
||||
<p class="text-sm text-slate-600 whitespace-pre-line">{{ los.beschreibung }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if los.abgrenzung %}
|
||||
<div class="card mt-6">
|
||||
<h2 class="text-sm font-semibold text-slate-700 mb-2">Abgrenzung</h2>
|
||||
<p class="text-sm text-slate-600 whitespace-pre-line">{{ los.abgrenzung }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Anforderungen -->
|
||||
<div class="card mt-6">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Anforderungen ({{ anforderungen.count }})</h2>
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_neu' ausschreibung.pk %}?los={{ los.pk }}"
|
||||
class="btn-ghost text-xs">+ Anforderung</a>
|
||||
</div>
|
||||
{% if anforderungen %}
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-slate-200 text-left text-xs text-slate-500">
|
||||
<th class="pb-2 pr-4">Titel</th>
|
||||
<th class="pb-2 pr-4">Verbindlichkeit</th>
|
||||
<th class="pb-2">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% for a in anforderungen %}
|
||||
<tr class="hover:bg-slate-50 {% if a.ausschlusskriterium and a.erfuellungsstatus == 'nicht_erfuellbar' %}bg-red-50{% endif %}">
|
||||
<td class="py-2 pr-4">
|
||||
<a href="{% url 'ausschreibungen:lose:anforderung_detail' ausschreibung.pk a.pk %}"
|
||||
class="text-brand-600 hover:underline">{{ a.titel }}</a>
|
||||
</td>
|
||||
<td class="py-2 pr-4">{% status_badge a.verbindlichkeit a.get_verbindlichkeit_display %}</td>
|
||||
<td class="py-2">{% status_badge a.erfuellungsstatus a.get_erfuellungsstatus_display %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="text-sm text-slate-500">Noch keine Anforderungen für dieses Los.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
56
vergabe_teilnahme/templates/lose/form.html
Normal file
56
vergabe_teilnahme/templates/lose/form.html
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}{{ titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1 class="page-title mb-6">{{ titel }}</h1>
|
||||
|
||||
<form method="post" class="max-w-2xl space-y-6">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card space-y-4">
|
||||
<h2 class="text-sm font-semibold text-slate-700">Los-Daten</h2>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Losnummer <span class="text-red-500">*</span></label>
|
||||
{{ form.losnummer }}
|
||||
{% if form.losnummer.errors %}<p class="text-xs text-red-600 mt-1">{{ form.losnummer.errors.0 }}</p>{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Lostitel <span class="text-red-500">*</span></label>
|
||||
{{ form.lostitel }}
|
||||
{% if form.lostitel.errors %}<p class="text-xs text-red-600 mt-1">{{ form.lostitel.errors.0 }}</p>{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Beschreibung</label>
|
||||
{{ form.beschreibung }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Abgrenzung</label>
|
||||
{{ form.abgrenzung }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Zuständiger</label>
|
||||
{{ form.zustaendiger }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Teilnahme</label>
|
||||
{{ form.teilnahme }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3">
|
||||
<button type="submit" class="btn-primary">Speichern</button>
|
||||
{% if los %}
|
||||
<a href="{% url 'ausschreibungen:lose:detail' ausschreibung.pk los.pk %}" class="btn-ghost">Abbrechen</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ausschreibungen:lose:liste' ausschreibung.pk %}" class="btn-ghost">Abbrechen</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
36
vergabe_teilnahme/templates/lose/liste.html
Normal file
36
vergabe_teilnahme/templates/lose/liste.html
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{% extends "base.html" %}
|
||||
{% load vergabe_tags %}
|
||||
{% block title %}Lose — {{ ausschreibung.titel }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h1 class="page-title">Lose</h1>
|
||||
<a href="{% url 'ausschreibungen:lose:neu' ausschreibung.pk %}" class="btn-primary text-xs">+ Los hinzufügen</a>
|
||||
</div>
|
||||
|
||||
{% if lose %}
|
||||
<div class="card">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-slate-200 text-left text-xs text-slate-500">
|
||||
<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">Teilnahme</th>
|
||||
<th class="pb-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="lose-table" class="divide-y divide-slate-100">
|
||||
{% for los in lose %}
|
||||
{% include "lose/partials/los_row.html" %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card text-center text-sm text-slate-500 py-8">
|
||||
Noch keine Lose angelegt.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
17
vergabe_teilnahme/templates/lose/loeschen_confirm.html
Normal file
17
vergabe_teilnahme/templates/lose/loeschen_confirm.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Los löschen{% endblock %}
|
||||
{% block content %}
|
||||
<div class="max-w-md mx-auto mt-16">
|
||||
<div class="card text-center space-y-4">
|
||||
<h1 class="text-lg font-semibold text-slate-800">Los löschen?</h1>
|
||||
<p class="text-sm text-slate-600">
|
||||
<strong>{{ los }}</strong> und alle zugehörigen Anforderungen werden unwiderruflich gelöscht.
|
||||
</p>
|
||||
<form method="post" class="flex justify-center gap-3">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn-primary bg-red-600 hover:bg-red-700">Löschen</button>
|
||||
<a href="{% url 'ausschreibungen:lose:detail' ausschreibung.pk los.pk %}" class="btn-ghost">Abbrechen</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{% load vergabe_tags %}
|
||||
<div id="erfuellungsstatus-widget-{{ anforderung.pk }}" class="flex items-center gap-2">
|
||||
{% status_badge anforderung.erfuellungsstatus anforderung.get_erfuellungsstatus_display %}
|
||||
<select name="erfuellungsstatus"
|
||||
hx-post="{% url 'ausschreibungen:lose:anforderung_status' anforderung.ausschreibung_id anforderung.pk %}"
|
||||
hx-target="#erfuellungsstatus-widget-{{ anforderung.pk }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="change"
|
||||
class="form-input text-xs py-0.5 h-7 w-auto">
|
||||
{% for val, label in anforderung.ERFUELLUNG_CHOICES %}
|
||||
<option value="{{ val }}" {% if val == anforderung.erfuellungsstatus %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
22
vergabe_teilnahme/templates/lose/partials/los_row.html
Normal file
22
vergabe_teilnahme/templates/lose/partials/los_row.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{% load vergabe_tags %}
|
||||
<tr class="hover:bg-slate-50">
|
||||
<td class="py-2 pr-4 text-slate-500">{{ los.losnummer }}</td>
|
||||
<td class="py-2 pr-4">
|
||||
<a href="{% url 'ausschreibungen:lose:detail' ausschreibung.pk los.pk %}"
|
||||
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">
|
||||
{% if los.teilnahme is None %}
|
||||
<span class="text-slate-400 text-xs">Offen</span>
|
||||
{% elif los.teilnahme %}
|
||||
<span class="text-green-600 text-xs font-medium">Ja</span>
|
||||
{% else %}
|
||||
<span class="text-red-600 text-xs font-medium">Nein</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="py-2 text-right">
|
||||
<a href="{% url 'ausschreibungen:lose:bearbeiten' ausschreibung.pk los.pk %}"
|
||||
class="btn-ghost text-xs">Bearbeiten</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
{% load vergabe_tags %}
|
||||
<div class="fixed inset-0 bg-black/40 flex items-center justify-center z-50"
|
||||
x-data @click.self="$el.remove()">
|
||||
<div class="bg-white rounded-xl shadow-xl w-full max-w-lg p-6" @click.stop>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-sm font-semibold text-slate-800">Nachweis zuordnen</h2>
|
||||
<button @click="$el.closest('.fixed').remove()" class="text-slate-400 hover:text-slate-600 text-lg leading-none">×</button>
|
||||
</div>
|
||||
|
||||
<form hx-get="{% url 'ausschreibungen:lose:nachweis_suche' ausschreibung_id anforderung.pk %}"
|
||||
hx-target="#nachweis-modal"
|
||||
hx-trigger="input delay:300ms"
|
||||
class="mb-4">
|
||||
<input type="text" name="q" value="{{ q }}"
|
||||
placeholder="Nachweis suchen…"
|
||||
class="form-input w-full" autofocus>
|
||||
</form>
|
||||
|
||||
{% if nachweise %}
|
||||
<ul class="divide-y divide-slate-100 max-h-64 overflow-y-auto text-sm">
|
||||
{% for n in nachweise %}
|
||||
<li class="py-2 flex items-center justify-between">
|
||||
<div>
|
||||
<span class="font-medium">{{ n.titel }}</span>
|
||||
{% if n.gueltig_bis %}
|
||||
<span class="ml-2 text-xs {% if n.ist_abgelaufen %}text-red-600{% else %}text-slate-500{% endif %}">
|
||||
bis {{ n.gueltig_bis }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% status_badge n.freigabestatus n.get_freigabestatus_display %}
|
||||
</div>
|
||||
{% if n.pk in bereits_zugeordnet %}
|
||||
<span class="text-xs text-green-600 font-medium">Bereits zugeordnet</span>
|
||||
{% else %}
|
||||
<form method="post"
|
||||
action="{% url 'ausschreibungen:lose:nachweis_zuordnen' ausschreibung_id anforderung.pk %}"
|
||||
hx-post="{% url 'ausschreibungen:lose:nachweis_zuordnen' ausschreibung_id anforderung.pk %}"
|
||||
hx-target="#nachweise-liste"
|
||||
hx-swap="innerHTML"
|
||||
hx-on::after-request="$el.closest('.fixed').remove()">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="nachweis_pk" value="{{ n.pk }}">
|
||||
<button type="submit" class="btn-ghost text-xs">Zuordnen</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="text-sm text-slate-500 text-center py-4">Keine Nachweise gefunden.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
{% load vergabe_tags %}
|
||||
{% with nachweise=anforderung.nachweise.all %}
|
||||
{% if nachweise %}
|
||||
<ul class="divide-y divide-slate-100 text-sm">
|
||||
{% for n in nachweise %}
|
||||
<li class="py-2 flex items-center justify-between">
|
||||
<div>
|
||||
<span class="font-medium">{{ n.titel }}</span>
|
||||
{% if n.ist_abgelaufen %}
|
||||
<span class="ml-2 text-xs text-red-600">abgelaufen</span>
|
||||
{% elif n.gueltig_bis %}
|
||||
<span class="ml-2 text-xs text-slate-500">bis {{ n.gueltig_bis }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<form method="post"
|
||||
action="{% url 'ausschreibungen:lose:nachweis_entfernen' ausschreibung_id anforderung.pk n.pk %}"
|
||||
hx-post="{% url 'ausschreibungen:lose:nachweis_entfernen' ausschreibung_id anforderung.pk n.pk %}"
|
||||
hx-target="#nachweise-liste"
|
||||
hx-swap="innerHTML">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="text-xs text-slate-400 hover:text-red-600">Entfernen</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="text-sm text-slate-500">Keine Nachweise zugeordnet.</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue