- Neues Modell DokumentDatei mit PostgreSQL FTS (SearchVectorField, GinIndex) - Upload-Pfad: dokumente/YYYY/MM/<uuid>/dateiname - 7 DMS-Views: list, detail, download, upload (HTMX Drag&Drop), delete, edit, search_api - Templates: list, detail, edit, upload mit Drag&Drop-Zone, Partials - URLs: /dms/ komplett verdrahtet - Sidebar: DMS als Primäreintrag, Paperless als Legacy - Migrationsskript: manage.py migrate_paperless_dokumente (DokumentLink → DokumentDatei) - compose.yml: paperless-Dienst deaktiviert (Legacy-Kommentarblock) - Migration 0048 angewendet Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
154 lines
8.7 KiB
HTML
154 lines
8.7 KiB
HTML
{% extends 'base.html' %}
|
||
{% load static %}
|
||
|
||
{% block title %}DMS – Dokumente – Stiftungsverwaltung{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||
<h1 class="h3">
|
||
<i class="fas fa-folder-open text-primary me-2"></i>
|
||
Dokumentenverwaltung (DMS)
|
||
</h1>
|
||
<a href="{% url 'stiftung:dms_upload' %}" class="btn btn-primary">
|
||
<i class="fas fa-upload me-2"></i>Dokument hochladen
|
||
</a>
|
||
</div>
|
||
|
||
<!-- Suche & Filter -->
|
||
<div class="card shadow mb-4">
|
||
<div class="card-body py-2">
|
||
<form method="get" class="row g-2 align-items-center">
|
||
<div class="col-md-5">
|
||
<div class="input-group input-group-sm">
|
||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||
<input type="text" name="q" value="{{ q }}" class="form-control"
|
||
placeholder="Volltextsuche (Titel, Beschreibung, Inhalt)"
|
||
hx-get="{% url 'stiftung:dms_search_api' %}"
|
||
hx-target="#search-results"
|
||
hx-trigger="keyup changed delay:400ms"
|
||
hx-include="[name='q']">
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<select name="kontext" class="form-select form-select-sm" onchange="this.form.submit()">
|
||
<option value="">Alle Typen</option>
|
||
{% for code, label in kontext_choices %}
|
||
<option value="{{ code }}" {% if code == kontext_filter %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<button type="submit" class="btn btn-sm btn-outline-primary w-100">Suchen</button>
|
||
</div>
|
||
{% if q or kontext_filter %}
|
||
<div class="col-md-2">
|
||
<a href="{% url 'stiftung:dms_list' %}" class="btn btn-sm btn-outline-secondary w-100">Reset</a>
|
||
</div>
|
||
{% endif %}
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- HTMX Live-Suchergebnisse -->
|
||
<div id="search-results"></div>
|
||
|
||
<!-- Dokument-Liste -->
|
||
<div class="card shadow">
|
||
<div class="card-header bg-dark text-white py-2 d-flex justify-content-between">
|
||
<span class="small fw-bold"><i class="fas fa-file me-2"></i>{{ gesamt }} Dokument(e)</span>
|
||
{% if q %}<span class="small text-warning">Suche: „{{ q }}"</span>{% endif %}
|
||
</div>
|
||
<div class="card-body p-0">
|
||
{% if page_obj.object_list %}
|
||
<div class="table-responsive">
|
||
<table class="table table-sm table-hover mb-0">
|
||
<thead class="table-light">
|
||
<tr>
|
||
<th>Titel</th>
|
||
<th>Typ</th>
|
||
<th>Zuordnung</th>
|
||
<th>Größe</th>
|
||
<th>Hochgeladen</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for dok in page_obj %}
|
||
<tr>
|
||
<td class="align-middle">
|
||
<a href="{% url 'stiftung:dms_detail' pk=dok.pk %}" class="text-decoration-none fw-semibold">
|
||
{% if dok.is_pdf %}<i class="fas fa-file-pdf text-danger me-1"></i>{% else %}<i class="fas fa-file text-muted me-1"></i>{% endif %}
|
||
{{ dok.titel|truncatechars:60 }}
|
||
</a>
|
||
{% if dok.beschreibung %}
|
||
<div class="small text-muted">{{ dok.beschreibung|truncatechars:80 }}</div>
|
||
{% endif %}
|
||
</td>
|
||
<td class="align-middle">
|
||
<span class="badge bg-secondary small">{{ dok.get_kontext_display }}</span>
|
||
</td>
|
||
<td class="align-middle small text-muted">
|
||
{% if dok.destinataer %}<div><i class="fas fa-user me-1"></i>{{ dok.destinataer.get_full_name }}</div>{% endif %}
|
||
{% if dok.land %}<div><i class="fas fa-map me-1"></i>{{ dok.land.lfd_nr }}</div>{% endif %}
|
||
{% if dok.paechter %}<div><i class="fas fa-user-tie me-1"></i>{{ dok.paechter.get_full_name }}</div>{% endif %}
|
||
</td>
|
||
<td class="align-middle small text-muted text-nowrap">{{ dok.get_human_size }}</td>
|
||
<td class="align-middle small text-muted text-nowrap">
|
||
{{ dok.erstellt_am|date:"d.m.Y" }}
|
||
{% if dok.erstellt_von %}<br>{{ dok.erstellt_von.get_full_name|default:dok.erstellt_von.username }}{% endif %}
|
||
</td>
|
||
<td class="align-middle text-end">
|
||
<a href="{% url 'stiftung:dms_download' pk=dok.pk %}" class="btn btn-xs btn-outline-success me-1" style="font-size:0.7rem;padding:2px 6px;" title="Herunterladen">
|
||
<i class="fas fa-download"></i>
|
||
</a>
|
||
<a href="{% url 'stiftung:dms_edit' pk=dok.pk %}" class="btn btn-xs btn-outline-secondary me-1" style="font-size:0.7rem;padding:2px 6px;" title="Bearbeiten">
|
||
<i class="fas fa-edit"></i>
|
||
</a>
|
||
<form method="post" action="{% url 'stiftung:dms_delete' pk=dok.pk %}" class="d-inline" onsubmit="return confirm('Dokument löschen?')">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="next" value="{% url 'stiftung:dms_list' %}">
|
||
<button type="submit" class="btn btn-xs btn-outline-danger" style="font-size:0.7rem;padding:2px 6px;" title="Löschen">
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<!-- Pagination -->
|
||
{% if page_obj.has_other_pages %}
|
||
<div class="d-flex justify-content-center py-3">
|
||
<nav>
|
||
<ul class="pagination pagination-sm mb-0">
|
||
{% if page_obj.has_previous %}
|
||
<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}&q={{ q }}&kontext={{ kontext_filter }}">‹</a></li>
|
||
{% endif %}
|
||
<li class="page-item active"><a class="page-link">{{ page_obj.number }}/{{ page_obj.paginator.num_pages }}</a></li>
|
||
{% if page_obj.has_next %}
|
||
<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}&q={{ q }}&kontext={{ kontext_filter }}">›</a></li>
|
||
{% endif %}
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
{% endif %}
|
||
{% else %}
|
||
<div class="text-muted text-center py-5">
|
||
<i class="fas fa-folder-open fa-3x mb-3 d-block opacity-25"></i>
|
||
{% if q %}Keine Dokumente für „{{ q }}" gefunden.{% else %}Noch keine Dokumente vorhanden.{% endif %}
|
||
<div class="mt-3">
|
||
<a href="{% url 'stiftung:dms_upload' %}" class="btn btn-primary btn-sm">
|
||
<i class="fas fa-upload me-1"></i>Erstes Dokument hochladen
|
||
</a>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|