- 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>
165 lines
7.6 KiB
HTML
165 lines
7.6 KiB
HTML
{% extends 'base.html' %}
|
||
{% load static %}
|
||
|
||
{% block title %}Dokument hochladen – Stiftungsverwaltung{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="row justify-content-center">
|
||
<div class="col-lg-8">
|
||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||
<h1 class="h3">
|
||
<i class="fas fa-upload text-primary me-2"></i>
|
||
Dokument hochladen
|
||
</h1>
|
||
<a href="{% url 'stiftung:dms_list' %}" class="btn btn-outline-secondary">
|
||
<i class="fas fa-arrow-left me-2"></i>Zurück
|
||
</a>
|
||
</div>
|
||
|
||
<form method="post" enctype="multipart/form-data" id="upload-form">
|
||
{% csrf_token %}
|
||
|
||
<!-- Drag & Drop Zone -->
|
||
<div class="card shadow mb-4">
|
||
<div class="card-body">
|
||
<div id="drop-zone"
|
||
class="border border-2 border-dashed rounded p-5 text-center"
|
||
style="border-color: #ccc !important; cursor: pointer; transition: all 0.2s;"
|
||
onclick="document.getElementById('datei-input').click()">
|
||
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3 d-block"></i>
|
||
<p class="mb-1 fw-semibold">Datei hierher ziehen oder klicken zum Auswählen</p>
|
||
<p class="small text-muted mb-0">PDF, Word, Excel, Bilder — max. 50 MB</p>
|
||
<div id="file-preview" class="mt-3 d-none">
|
||
<span class="badge bg-success fs-6 px-3 py-2">
|
||
<i class="fas fa-file me-2"></i><span id="file-name"></span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<input type="file" name="datei" id="datei-input" class="d-none" required>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Metadaten -->
|
||
<div class="card shadow mb-4">
|
||
<div class="card-header bg-dark text-white py-2">
|
||
<span class="small fw-bold"><i class="fas fa-tag me-2"></i>Metadaten</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Titel</label>
|
||
<input type="text" name="titel" class="form-control"
|
||
placeholder="Wird automatisch aus Dateiname abgeleitet wenn leer">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Typ / Kontext</label>
|
||
<select name="kontext" class="form-select">
|
||
{% for code, label in kontext_choices %}
|
||
<option value="{{ code }}" {% if code == initial.kontext %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Beschreibung <span class="text-muted fw-normal">(optional)</span></label>
|
||
<textarea name="beschreibung" class="form-control" rows="2"
|
||
placeholder="Kurze Beschreibung des Dokuments"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Zuordnung -->
|
||
<div class="card shadow mb-4">
|
||
<div class="card-header bg-dark text-white py-2">
|
||
<span class="small fw-bold"><i class="fas fa-link me-2"></i>Zuordnung <span class="fw-normal opacity-75">(optional)</span></span>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<label class="form-label small fw-semibold">Destinatär</label>
|
||
<select name="destinataer_id" class="form-select form-select-sm">
|
||
<option value="">– keine –</option>
|
||
{% for d in destinataere %}
|
||
<option value="{{ d.pk }}" {% if d.pk|stringformat:'s' == initial.destinataer_id %}selected{% endif %}>
|
||
{{ d.get_full_name }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label class="form-label small fw-semibold">Länderei</label>
|
||
<select name="land_id" class="form-select form-select-sm">
|
||
<option value="">– keine –</option>
|
||
{% for l in laendereien %}
|
||
<option value="{{ l.pk }}" {% if l.pk|stringformat:'s' == initial.land_id %}selected{% endif %}>
|
||
{{ l.lfd_nr }}{% if l.gemeinde %} – {{ l.gemeinde }}{% endif %}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label class="form-label small fw-semibold">Pächter</label>
|
||
<select name="paechter_id" class="form-select form-select-sm">
|
||
<option value="">– keine –</option>
|
||
{% for p in paechter_qs %}
|
||
<option value="{{ p.pk }}" {% if p.pk|stringformat:'s' == initial.paechter_id %}selected{% endif %}>
|
||
{{ p.get_full_name }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="d-flex gap-2 justify-content-end">
|
||
<a href="{% url 'stiftung:dms_list' %}" class="btn btn-outline-secondary">Abbrechen</a>
|
||
<button type="submit" class="btn btn-primary">
|
||
<i class="fas fa-upload me-2"></i>Hochladen
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
const dropZone = document.getElementById('drop-zone');
|
||
const fileInput = document.getElementById('datei-input');
|
||
const filePreview = document.getElementById('file-preview');
|
||
const fileName = document.getElementById('file-name');
|
||
|
||
function showFile(file) {
|
||
fileName.textContent = file.name;
|
||
filePreview.classList.remove('d-none');
|
||
dropZone.style.borderColor = '#198754 !important';
|
||
dropZone.classList.add('border-success');
|
||
}
|
||
|
||
fileInput.addEventListener('change', function () {
|
||
if (this.files[0]) showFile(this.files[0]);
|
||
});
|
||
|
||
dropZone.addEventListener('dragover', function (e) {
|
||
e.preventDefault();
|
||
this.style.backgroundColor = '#f0f7ff';
|
||
this.style.borderColor = '#0d6efd';
|
||
});
|
||
|
||
dropZone.addEventListener('dragleave', function () {
|
||
this.style.backgroundColor = '';
|
||
this.style.borderColor = '#ccc';
|
||
});
|
||
|
||
dropZone.addEventListener('drop', function (e) {
|
||
e.preventDefault();
|
||
this.style.backgroundColor = '';
|
||
this.style.borderColor = '#ccc';
|
||
const files = e.dataTransfer.files;
|
||
if (files.length > 0) {
|
||
fileInput.files = files;
|
||
showFile(files[0]);
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
{% endblock %}
|