bericht/ajax/page_bulk.php
Eduard Wisch 4102ebfe5b
All checks were successful
Deploy bericht / deploy (push) Successful in 13s
Editor-Ueberarbeitung 1.5.0: Anhaenge-Kacheln, echte Seitengeometrie, Arbeiten ohne Reload [deploy]
Anhaenge-Spalte: Kachelraster mit Server-Thumbnails statt Dateinamen-Liste (Bilder per GD,
PDFs per PDF.js), Grossansicht per Klick, Auswahlreihenfolge sichtbar, Sortierung/Filter
(Aufnahmezeit per eigenem EXIF-Parser, da im Prod-Container ohne exif-Modul), ziehbare
Spaltenbreite, Kachelgroesse, Drag & Drop auf Seitenliste/Arbeitsflaeche/Raster-Plaetze.

Arbeitstisch zeigt jetzt Kopf-, Inhalts- und Fussbereich passend zur echten Seitengeometrie
(bericht_page_geometry()) - Editor und PDF-Erzeugung rechnen mit denselben Werten, das PDF
setzt die Arbeitsflaeche 1:1 statt sie ein zweites Mal einzupassen.

Neu: Bild einer Seite austauschen (auch einzelne Raster-Plaetze), Seiten mehrfach markieren
und sammeln loeschen/duplizieren, Autosave mit Verlassen-Warnung, Tastenkuerzel, kein
location.reload() mehr nach Hinzufuegen/Loeschen/Hochladen (ajax/fragments.php).

Nebenbei behoben: dol_dir_list() ohne mode=1 (Dateigroesse leer), PDF.js-Worker-Pfad ohne
/custom-Praefix, PDFs liefen als Download statt inline, Groessen-Select blieb leer,
Mehrfach-Upload nahm nur die erste Datei, Race-Condition bei schnellem Seitenwechsel.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 00:33:20 +02:00

105 lines
3.9 KiB
PHP

<?php
/* Sammelaktionen auf Seiten eines Berichts.
*
* POST: berichtid, action = delete | duplicate, pageids = JSON-Array, token
*
* Ersetzt das seitenweise Loeschen, wenn mehrere Seiten markiert sind, und
* legt beim Duplizieren eine Kopie direkt hinter dem Original an (inklusive
* Anmerkungen, Notiz und — bei Rastern — der Bilder in den Plaetzen).
*/
require_once __DIR__.'/_inc.php';
global $db, $user;
if (!$user->hasRight('bericht', 'write')) bericht_ajax_fail('Permission denied', 403);
$berichtid = (int) ($_POST['berichtid'] ?? 0);
$action = (string) ($_POST['action'] ?? '');
$ids_raw = (string) ($_POST['pageids'] ?? '[]');
if (!$berichtid) bericht_ajax_fail('berichtid fehlt');
if (!in_array($action, array('delete', 'duplicate'), true)) bericht_ajax_fail('Unbekannte Aktion');
$ids = json_decode($ids_raw, true);
if (!is_array($ids) || empty($ids)) bericht_ajax_fail('Keine Seiten ausgewählt');
$ids = array_values(array_unique(array_filter(array_map('intval', $ids))));
if (empty($ids)) bericht_ajax_fail('Keine gültigen Seiten');
$b = new Bericht($db);
if ($b->fetch($berichtid) <= 0) bericht_ajax_fail('Bericht nicht gefunden', 404);
if ((int) $b->status === Bericht::STATUS_FINAL) {
bericht_ajax_fail('Der Bericht ist finalisiert und kann nicht mehr geändert werden', 403);
}
// Nur Seiten dieses Berichts anfassen
$in = implode(',', $ids);
$check = $db->query("SELECT rowid FROM ".$db->prefix()."bericht_page"
." WHERE rowid IN (".$in.") AND fk_bericht = ".((int) $berichtid));
if (!$check) bericht_ajax_fail($db->lasterror());
$valid = array();
while ($r = $db->fetch_object($check)) $valid[] = (int) $r->rowid;
if (count($valid) !== count($ids)) bericht_ajax_fail('Seiten gehören nicht zu diesem Bericht', 403);
$db->begin();
if ($action === 'delete') {
$sql = "DELETE FROM ".$db->prefix()."bericht_page WHERE rowid IN (".implode(',', $valid).")";
if (!$db->query($sql)) {
$db->rollback();
bericht_ajax_fail($db->lasterror());
}
bericht_renumber_pages($db, $berichtid);
$db->commit();
bericht_ajax_ok(array('deleted' => count($valid)));
}
/* --- Duplizieren --- */
$pages = BerichtPage::fetchAllForBericht($db, $berichtid);
$by_id = array();
foreach ($pages as $p) $by_id[(int) $p->id] = $p;
$created = 0;
foreach ($valid as $pid) {
if (!isset($by_id[$pid])) continue;
$src = $by_id[$pid];
$copy = new BerichtPage($db);
$copy->fk_bericht = $berichtid;
// Vorlaeufig ans Ende; die endgueltige Reihenfolge macht die Neunummerierung
$copy->page_order = 9000 + (int) $src->page_order;
$copy->source_type = $src->source_type;
$copy->source_path = $src->source_path;
$copy->source_page = $src->source_page;
$copy->rotation = $src->rotation;
$copy->fabric_json = $src->fabric_json;
$copy->note = $src->note;
$copy->title = $src->title;
$copy->layout = $src->layout;
$copy->image_scale = $src->image_scale;
$copy->image_align = $src->image_align;
$newid = $copy->create();
if ($newid <= 0) {
$db->rollback();
bericht_ajax_fail('Kopie konnte nicht angelegt werden');
}
// Bilder der Plaetze mitkopieren (Raster-Layouts)
if ($src->layout !== 'single') {
foreach ($src->getImages() as $img) {
if ($copy->setSlotImage($img['slot'], $img['source_path'], $img['rotation']) <= 0) {
$db->rollback();
bericht_ajax_fail('Bilder der Kopie konnten nicht angelegt werden');
}
}
}
// composite_path bewusst NICHT kopieren: die Kopie erzeugt beim ersten
// Speichern ihr eigenes, sonst zeigen beide Seiten auf dieselbe Datei
// und das Bearbeiten der einen ueberschreibt die andere.
$created++;
}
// Kopien direkt hinter ihr Original einsortieren
bericht_reorder_with_copies($db, $berichtid, $valid);
$db->commit();
bericht_ajax_ok(array('created' => $created));