All checks were successful
Deploy bericht / deploy (push) Successful in 13s
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>
105 lines
3.9 KiB
PHP
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));
|