Die API-Seite zur Baustelle-PWA holt nach, was der Editor mit 1.5.0 bekommen hat.
photo.php kann jetzt size=thumb&w=<px> und rendert ueber bericht_attachment_thumb()
(GD, Cache, EXIF-Rotation) statt die Originaldatei auszuliefern. size=small konnte nur
ein von Dolibarr vorgefertigtes thumbs/<name>_small.<ext> liefern - fuer Uploads ueber
orders.php?action=upload_photo gibt es das nicht, dort laeuft kein vignette(). Die PWA
lud dadurch fuer jede Kachel das komplette Foto: gemessen 9,8 KB statt 235 KB je Kachel.
Antwort mit ETag aus der mtime, Folgeaufrufe enden mit 304.
orders.php?action=photos liefert taken_at (EXIF-Aufnahmezeit ueber bericht_file_taken_at,
sonst Dateidatum) und sortiert danach statt nach filemtime.
reports.php gibt je Seite title und composite_path aus. title konnte ueber pages.php
gesetzt werden, kam aber nie zurueck. composite_path ist das im Editor gebaute
Seitenbild - ohne das zeigen Clients nur das Rohbild ohne Anmerkungen, bei
Raster-Layouts eines von bis zu sechs Bildern und bei title_only gar keins.
Neu: api/note.php - Textnotizen zum Auftrag, aufgebaut wie die Sprachnotiz. Die Notiz
liegt als notiz_<betreff>_<datum>.txt im Auftragsverzeichnis und ist damit auch im
Dolibarr-Auftrag und in der Anhaenge-Spalte des Editors sichtbar. Liste, Lesen, Anlegen,
Aendern, Loeschen. Der file-Parameter wird gegen ^notiz_[A-Za-z0-9_.-]*\.txt$ geprueft;
gegen Pfad-Ausbrueche getestet.
ROADMAP.md wiederhergestellt - sie war mit eb37a4b geloescht worden, weil alle Punkte
abgehakt waren. Sie bleibt ab jetzt liegen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
193 lines
12 KiB
Markdown
193 lines
12 KiB
Markdown
# ROADMAP — Modul Bericht
|
||
|
||
Stand: 2026-08-22 · Version im Repo: 1.5.1
|
||
|
||
> Diese Datei war mit `eb37a4b` gelöscht worden, weil alle Punkte abgehakt waren. Sie bleibt
|
||
> ab jetzt liegen — erledigte Punkte werden abgehakt, nicht entfernt.
|
||
|
||
---
|
||
|
||
## 0. API-Seite für die Baustelle-PWA ✅ 1.5.1
|
||
|
||
Die PWA (`data/baustelle-pwa`) spricht ausschließlich `api/`. Mit 1.5.0 war Infrastruktur
|
||
entstanden, die dort nicht ankam — mit 1.5.1 nachgezogen. Gegenstück: `ROADMAP.md` im PWA-Repo, Abschnitt 1.
|
||
|
||
- [x] **`api/photo.php`: `size=thumb&w=<px>`** ✅ 1.5.1 — bis dahin lieferte der Endpoint nur ein Thumbnail,
|
||
wenn Dolibarr schon eines unter `thumbs/<name>_small.<ext>` erzeugt hat. Fotos aus der PWA
|
||
kommen über `orders.php?action=upload_photo` herein, und dort läuft **kein `vignette()`** —
|
||
es gibt also nie eins, und die PWA lädt für jede Kachel das volle Foto.
|
||
`bericht_attachment_thumb()` (1.5.0, GD + Cache + EXIF-Rotation) macht genau das Richtige
|
||
und ist über die bereits eingebundene `lib/bericht.lib.php` erreichbar.
|
||
Dazu ETag aus der mtime, damit wiederholte Aufrufe mit 304 enden.
|
||
- [x] **`api/orders.php?action=photos`: `taken_at`** ✅ 1.5.1 — sortiert wurde nach `filemtime`.
|
||
Der Editor nutzt seit 1.5.0 die EXIF-Aufnahmezeit (`bericht_file_taken_at()`, eigener
|
||
Parser weil im Prod-Container kein `exif`-Modul). Bei Uploads aus der Galerie ist die
|
||
Upload-Zeit die falsche Reihenfolge.
|
||
- [x] **`api/reports.php`: `title` im `pages`-Array** ✅ 1.5.1 — `api/pages.php` konnte den Seitentitel
|
||
setzen und die PWA rendert ihn, aber das Detail gab ihn nicht aus. Der Titel wirkte in der
|
||
PWA deshalb, als würde er nicht gespeichert.
|
||
- [x] **`api/reports.php`: `composite_path` im `pages`-Array** ✅ 1.5.1 — die PWA zeigte `source_path`,
|
||
also das Rohbild ohne Anmerkungen. Bei Raster-Layouts (`grid_2` … `grid_6`,
|
||
`before_after`) ist das nur eines von bis zu sechs Bildern, bei `title_only` gar keins
|
||
(die PWA zeigte dann eine ❌-Kachel).
|
||
- [x] **Neu: `api/note.php`** ✅ 1.5.1 — Textnotizen zum Auftrag (Liste, Lesen, Anlegen, Ändern,
|
||
Löschen). Ablage wie bei der Sprachnotiz: `notiz_<betreff>_<datum>.txt` im
|
||
Auftrags-Verzeichnis, damit die Notiz auch im Dolibarr-Auftrag und in der Anhänge-Spalte
|
||
des Editors auftaucht. Der `file`-Parameter ist gegen ein Muster geprüft (Pfad-Ausbruch).
|
||
|
||
Gegenstück in der PWA: siehe `ROADMAP.md` im Repo `baustelle-pwa`, Abschnitte 1 und 3 —
|
||
dort ebenfalls erledigt.
|
||
|
||
---
|
||
|
||
## 1. Anhänge-Spalte (links im Editor) — Hauptbaustelle
|
||
|
||
Ausgangslage (Eddy, 21.08.2026): *„die Dateinamen können in dem schmalen Fenster nicht ganz
|
||
angezeigt werden, ich habe Schwierigkeiten die richtigen Bilder auszusuchen."*
|
||
Die Spalte ist 260 px breit und zeigt pro Datei nur eine Zeile `🖼 langer_dateiname… 2,3 MB 🗑️`.
|
||
Bei 20–40 Baustellenfotos mit Namen wie `IMG_20260812_141233_HDR.jpg` ist das unbrauchbar.
|
||
|
||
### 1.1 Miniatur-Vorschau statt Dateiname ✅ 1.5.0
|
||
- [x] Kachel-Raster (2 Spalten) statt Liste
|
||
- [x] Server-Thumbnails für Bilder (GD, gecacht) — Original-Handyfotos werden **nicht** mehr voll geladen
|
||
- [x] PDF-Anhänge: Seite 1 als Miniatur (PDF.js, clientseitig, lazy)
|
||
- [x] Klick auf Miniatur → Lightbox (Zoom/Pan/Swipe), `✕` bzw. Esc schließt — PDFs im Vollbild-Viewer
|
||
- [x] Dateiname zweizeilig unter der Kachel + voller Name als Tooltip
|
||
|
||
### 1.2 Auswahl bedienbar machen ✅ 1.5.0
|
||
- [x] Checkbox als Overlay auf der Kachel (großes Klickziel), Klick auf die Namenszeile wählt ebenfalls aus
|
||
- [x] Auswahl-Reihenfolge sichtbar (① ② ③) — bestimmt die Slot-Reihenfolge im Grid-Layout
|
||
(vorher: DOM-Reihenfolge, also nicht steuerbar)
|
||
- [x] „Alle / Keine" pro Herkunfts-Gruppe + Zähler „3 ausgewählt"
|
||
- [x] Bereits im Bericht verwendete Anhänge werden markiert (✓-Badge, ausgegraut)
|
||
|
||
### 1.3 Sortierung und Filter ✅ 1.5.0
|
||
- [x] Sortierung nach **Aufnahmezeit** (auf- und absteigend), Name, Größe — jeweils innerhalb der
|
||
Herkunfts-Gruppe, damit die Zuordnung zum Beleg erhalten bleibt
|
||
- [x] Filter: alle · nur Bilder · nur PDFs · noch nicht verwendet
|
||
- [x] Aufnahmezeit steht unter der Kachel (`12.08. 11:48 · 56 Kb`)
|
||
- [x] EXIF-Parser in PHP (`bericht_jpeg_taken_at`), weil das `exif`-Modul im Container
|
||
`90-Dolibarr-Prod-Custom` **nicht geladen** ist. Gegen das PHP-Modul geprüft: identische Werte.
|
||
Fallback auf das Dateidatum, wenn kein EXIF vorhanden ist.
|
||
- [x] Auswahl von Sortierung/Filter/Ansicht wird gemerkt (localStorage)
|
||
|
||
### 1.4 Spaltenbreite, Kachelgröße, Ziehen und Ablegen ✅ 1.5.0
|
||
- [x] **Spaltenbreite ziehbar** — Trennlinie zwischen Anhängen und Arbeitsfläche (150–620 px),
|
||
Doppelklick setzt auf 260 px zurück; Breite wird gemerkt
|
||
- [x] **Ein-/ausklappbar** über „«" in der Kopfzeile — eingeklappt bleiben 26 px stehen
|
||
- [x] **Kachelgröße** klein / mittel / groß über „⤢" (in der kleinsten Stufe entfällt die Größenangabe)
|
||
- [x] **Kachel auf die Seitenliste ziehen** → neue Seite(n). Sind mehrere Kacheln angekreuzt und man
|
||
zieht eine davon, kommen alle mit.
|
||
- [x] **Kachel auf die Arbeitsfläche ziehen** → ersetzt das Bild der offenen Seite
|
||
- [x] **Kachel auf einen Raster-Platz ziehen** → setzt genau diesen Platz
|
||
- [x] **Dateien vom Rechner auf die Spalte ziehen** → Upload (nicht unterstützte Typen werden
|
||
benannt und übersprungen)
|
||
- [x] SortableJS bekam `group: {put: false}` — sonst streiten sich Sortierung und Ablegen um die
|
||
gleichen Ereignisse
|
||
|
||
---
|
||
|
||
## 2. Seitenansicht ("Arbeitstisch") ✅ 1.5.0
|
||
|
||
Vorher zeigte der Editor ein A4-Blatt, auf dem das Foto formatfüllend lag. Beim PDF wurde
|
||
dieses ganze Blatt **nochmal** in den Satzspiegel eingepasst — der Inhalt schrumpfte also ein
|
||
zweites Mal, und die Vorschau entsprach nicht dem Ergebnis. Seiten, die nie im Editor
|
||
gespeichert wurden, liefen zudem über den Kopfbereich (Logo/Titel) hinweg.
|
||
|
||
- [x] Eine gemeinsame Geometrie-Quelle: `bericht_page_geometry($format, $orientation, $has_note)`
|
||
in `lib/bericht.lib.php` — liefert Seitenmaß, Ränder (10 mm), Kopfbereich (30 mm),
|
||
Fußbereich (16 mm), Notizzone und den Inhaltsbereich. Editor **und** PDF rechnen damit.
|
||
- [x] Arbeitsfläche = Inhaltsbereich. Drumherum das Blatt mit schraffierter Kopf-/Fußzone
|
||
(das, was TCPDF selbst druckt) und einer Notizzone, sobald die Seite eine Notiz hat.
|
||
- [x] PDF setzt das Composite 1:1 in den Inhaltsbereich statt es erneut einzupassen
|
||
- [x] Alle Layout-Zweige der PDF-Erzeugung (Einzelbild, Raster, Vorher/Nachher, Notiz)
|
||
auf dieselbe Geometrie umgestellt — vorher rechneten sie mit `margin = 10` ab
|
||
Blattkante und schoben Bilder unter den Kopfbereich
|
||
- [x] Raster-Vorschau (`ajax/page_image.php`) rendert im Format des Inhaltsbereichs
|
||
- [x] Umschalter „📐 Rand" in der Werkzeugleiste (Zustand wird gemerkt)
|
||
- [x] Rückwärtskompatibel: Composites aus der Zeit davor haben Blatt-Proportion und werden
|
||
an der Proportion erkannt und proportional eingepasst statt verzerrt
|
||
|
||
---
|
||
|
||
## 3. Bild einer Seite austauschen ✅ 1.5.0
|
||
|
||
- [x] `ajax/replace_page_source.php` — tauscht die Quelle einer Seite; Reihenfolge, Notiz und
|
||
Anmerkungen bleiben erhalten (vorher: Seite löschen und hinten neu anhängen)
|
||
- [x] Raster-Seiten: einzelner Platz austauschbar (nutzt das vorhandene `set_slot_image.php`,
|
||
für das es bis dahin keine Bedienung gab)
|
||
- [x] Bedienung: „🔄" auf der Seitenminiatur → Statusleiste am unteren Rand → links auf das
|
||
Ersatzbild klicken. Esc bricht ab. Bei Rastern vorher den Platz (1…n) wählen.
|
||
- [x] Finalisierte Berichte werden serverseitig abgewiesen
|
||
|
||
---
|
||
|
||
## 4. Editor / Arbeitsablauf
|
||
|
||
- [x] **Kein `location.reload()` mehr** ✅ 1.5.0 — Hinzufügen, Löschen, Hochladen, Bildtausch und
|
||
der QR-Upload aktualisieren nur noch die betroffenen Listen. Neuer Endpoint
|
||
`ajax/fragments.php` liefert Seiten- und Anhängeliste als HTML; gerendert wird über
|
||
`bericht_print_page_list()` / `bericht_print_attachment_list()`, dieselben Funktionen wie beim
|
||
Seitenaufbau. Der Editor bleibt auf der bearbeiteten Seite, Zoom und Ansicht bleiben erhalten.
|
||
Einzige Ausnahme: nach dem Finalisieren wird bewusst neu geladen, weil der Bericht den Status
|
||
wechselt und die ganze Karte anders aussieht.
|
||
- [x] **Autosave** ✅ 1.5.0 — 4 Sekunden nach der letzten Änderung wird gespeichert, ebenso beim
|
||
Seitenwechsel und beim Wegschalten des Tabs. Zustand steht in der Fußleiste
|
||
(„● nicht gespeichert" / „✓ gespeichert"), beim Verlassen der Seite warnt der Browser.
|
||
Wichtig: das Aufbauen einer Seite (und Zoomen) löst Fabric-Events aus, zählt aber nicht als
|
||
Änderung — sonst stünde direkt nach dem Öffnen „nicht gespeichert" da.
|
||
- [x] **Tastenkürzel** ✅ 1.5.0 — V/P/R/K/A/T für die Werkzeuge, Entf löscht die Auswahl (das
|
||
Hintergrundbild ist ausgenommen), Strg+Z/Y, Strg+S, ↑/↓ blättert durch die Seiten.
|
||
In Eingabefeldern und bei offenem Dialog oder offener Großansicht greifen sie nicht.
|
||
Die Kürzel stehen in den Tooltips der Schaltflächen.
|
||
- [x] **Seitenliste: Mehrfachauswahl** ✅ 1.5.0 — Klick auf die Seitennummer markiert, Umschalt
|
||
erweitert bis dorthin. Sammelleiste mit Verdoppeln (⧉), Löschen (🗑️) und Aufheben (Esc).
|
||
Neuer Endpoint `ajax/page_bulk.php`; Kopien landen direkt hinter ihrem Original
|
||
(`bericht_reorder_with_copies()`), nach dem Löschen wird lückenlos neu nummeriert.
|
||
`composite_path` wird bewusst **nicht** mitkopiert — sonst zeigten beide Seiten auf dieselbe
|
||
Datei und das Bearbeiten der einen überschriebe die andere.
|
||
- [x] **Raster-Plätze direkt anklicken** ✅ 1.5.0 — über der Arbeitsfläche liegt ein Gitter mit
|
||
einer Schaltfläche je Platz (bei Vorher/Nachher entsprechend beschriftet). Klick setzt das
|
||
links ausgewählte Bild, Ablegen per Drag setzt das gezogene. Die Aufteilung entspricht
|
||
`BerichtPage::slotRectsInBox()`. Die Plätze reagieren nur im Auswahlmodus — beim Zeichnen
|
||
haben die Werkzeuge Vorrang, sonst käme man auf Raster-Seiten nicht mehr zum Zeichnen.
|
||
- [x] **Seitenwechsel serialisiert** ✅ 1.5.0 — beim schnellen Durchklicken überlappten sich zwei
|
||
Durchläufe von `loadPage()`: der zweite speicherte die noch nicht umgeschaltete Seite ein
|
||
zweites Mal, und beide rendern in denselben Canvas — so konnte die Notiz der einen Seite bei
|
||
der anderen landen. Jeder Aufruf bekommt jetzt eine Nummer und bricht ab, sobald ein neuerer
|
||
gestartet ist.
|
||
|
||
## 5. Kleinkram / Fixes
|
||
|
||
- [x] **Mehrfach-Upload**: `bindExtraUpload` verarbeitete nur `inp.files[0]` — Mehrfachauswahl im
|
||
Dateidialog war möglich, es kam aber nur eine Datei an ✅ 1.5.0
|
||
- [x] Upload-Fortschritt ✅ 1.5.0 — der Knopf zeigt beim Mehrfach-Upload „⏳ 3 / 8"
|
||
- [x] `att-delete` löscht die Datei wirklich aus den Dokumenten des Belegs ✅ 1.5.0 — der Dialog
|
||
sagt das jetzt deutlich und warnt zusätzlich, wenn die Datei im Bericht in Gebrauch ist.
|
||
|
||
---
|
||
|
||
## Erledigt
|
||
|
||
### 1.5.1 — 2026-08-22
|
||
API-Seite zur PWA nachgezogen (Abschnitt 0): Thumbnail-Endpoint `size=thumb` statt Ausliefern
|
||
der Originaldateien (9,8 KB statt 235 KB je Kachel, mit ETag/304), EXIF-Aufnahmezeit in der
|
||
Anhängeliste, `title` und `composite_path` in der Bericht-Detailantwort, neuer Endpoint
|
||
`api/note.php` für Textnotizen.
|
||
|
||
### 1.5.0 — 2026-08-21
|
||
Vollständig abgearbeitet. Anhänge-Kachelraster mit Miniaturen (1.1–1.4), Server-Thumbnail-Endpoint,
|
||
PDF-Lightbox, Arbeitstisch mit echter Seitengeometrie (2), Bildaustausch auf bestehenden Seiten (3),
|
||
Arbeiten ohne Neuladen, Autosave, Tastenkürzel, Sammelaktionen auf Seiten und Raster-Plätze (4).
|
||
|
||
Nebenbei gefundene und behobene Fehler:
|
||
- `dol_dir_list()` wurde ohne `$mode = 1` aufgerufen — dadurch waren `size` und `date` leer
|
||
und in der Anhängeliste stand „ Bytes" ohne Zahl
|
||
- PDF.js-Worker-Pfad war hartkodiert ohne `/custom`-Präfix → PDF.js lief im „fake worker"-Modus
|
||
auf dem Hauptthread (spürbar langsamer beim Rendern)
|
||
- `document.php` wurde ohne `attachment=0` verlinkt → PDFs wurden heruntergeladen statt angezeigt
|
||
- Größen-Auswahl der Seite blieb leer, weil der DB-Wert `1` die Option `1.0` nicht traf
|
||
- Mehrfach-Upload nahm nur die erste Datei
|
||
- `--inputbackgroundcolor` wurde im Modul als „im AwlDark nicht vorhanden" behandelt; die
|
||
Variable existiert (KB #512, per DevTools bestätigt) — Editor-Eingabefelder nutzen jetzt
|
||
dieselben Farben wie Dolibarr selbst
|