All checks were successful
Deploy bericht / deploy (push) Successful in 2s
Paradigmen-Wechsel: Editor rendert bei jedem Save sein Fabric-Canvas als PNG und lädt es hoch. PDF nutzt dieses PNG 1:1 statt die Shapes serverseitig nachzuzeichnen. Damit ist garantiert: was du im Editor siehst, ist EXAKT das was im PDF landet. Alle Pfeil/Text/Shape-Rendering-Bugs zwischen Fabric-JSON und PHP-Nachzeichnung sind Geschichte. Kernänderungen: 1. DB: Neue Spalte bericht_page.composite_path (Migration im init()) 2. ajax/save_annotations.php: nimmt multipart file 'composite' entgegen, speichert es unter bericht/work/<fkb>/composite_<pid>.png 3. lib/bericht.lib.php: bericht_render_page_to_pdf prüft composite_path zuerst — wenn vorhanden, wird eine Seite mit genau diesem PNG als volles Bild gerendert, fertig. Fallback auf alte Logik bei alten Berichten ohne Composite. 4. editor.js renderImage: Quellbild wird NICHT mehr auf pdfCanvas gezeichnet, sondern als fabric.Image ins Fabric-Canvas geladen — ZIEHBAR, SKALIERBAR, ROTIERBAR wie jedes andere Objekt. Mehrere Bilder auf einer Seite kein Problem mehr. 5. editor.js savePageAnnotations: nach Shape-State wird toDataURL mit multiplier:2 aufgerufen, PNG-Blob hochgeladen zusammen mit fabric_json (für spätere Edits) und note. 6. editor.js loadPage: wenn fabric_json existiert, wird dieses clientseitig wieder eingeladen (inkl. eingebettete Bilder) — das Quell-Bild wird nicht mehr neu aus der Quelle geholt. Bei leerer Seite läuft der alte Render-Flow. Phase 6 Bonus — Text mit Hintergrund: - Neuer color-picker 'BG:' in der Toolbar + 'Ø'-Button (kein BG) - Fabric IText bekommt textBackgroundColor + padding:6 - Bei selektiertem Text-Objekt wird BG live angewendet - Dataset-Flag 'active' toggelt zwischen ein/aus Dark-Input-Fix: - Textarea in .bericht-page-note nutzte --inputbackgroundcolor (existiert in awl-dark nicht → Fallback #fff = weiße Fläche mit schwarzer Schrift auf Dark-Theme) - Jetzt: --colorbackbody + --colortext + --colorboxbordertitle1 - Generischer Input-Style für alle Text-Eingaben in .bericht-editor Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> [deploy]
60 lines
2.4 KiB
PHP
60 lines
2.4 KiB
PHP
<?php
|
|
/* Speichert Fabric.js-JSON + Notiz + optional Composite-PNG für eine Seite.
|
|
*
|
|
* POST:
|
|
* pageid — Seiten-ID
|
|
* fabric_json — Fabric-Serialisierung (für späteren Edit)
|
|
* note — Notiz für den PDF-Footer
|
|
* rotation — Rotation 0/90/180/270
|
|
* composite — (optional) multipart/form-data file: PNG der kompletten Seite
|
|
* token
|
|
*/
|
|
require_once __DIR__.'/_inc.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|
|
|
global $db, $user;
|
|
if (!$user->hasRight('bericht', 'write')) bericht_ajax_fail('Permission denied', 403);
|
|
|
|
$pageid = (int) ($_POST['pageid'] ?? 0);
|
|
if (!$pageid) bericht_ajax_fail('pageid fehlt');
|
|
|
|
$fabric = (string) ($_POST['fabric_json'] ?? '');
|
|
$note = (string) ($_POST['note'] ?? '');
|
|
$rotation = (int) ($_POST['rotation'] ?? 0);
|
|
$rotation = (($rotation % 360) + 360) % 360;
|
|
|
|
// Page laden und fk_bericht ermitteln
|
|
$res = $db->query("SELECT rowid, fk_bericht FROM ".$db->prefix()."bericht_page WHERE rowid = ".((int) $pageid));
|
|
if (!$res || !($row = $db->fetch_object($res))) bericht_ajax_fail('Page nicht gefunden', 404);
|
|
$fk_bericht = (int) $row->fk_bericht;
|
|
|
|
// Composite-PNG speichern wenn hochgeladen
|
|
$composite_relpath = null;
|
|
if (!empty($_FILES['composite']['tmp_name']) && is_uploaded_file($_FILES['composite']['tmp_name'])) {
|
|
$workdir = DOL_DATA_ROOT.'/bericht/work/'.$fk_bericht;
|
|
if (!is_dir($workdir)) dol_mkdir($workdir);
|
|
$filename = 'composite_'.$pageid.'.png';
|
|
$target = $workdir.'/'.$filename;
|
|
if (move_uploaded_file($_FILES['composite']['tmp_name'], $target)) {
|
|
$composite_relpath = str_replace(DOL_DATA_ROOT.'/', '', $target);
|
|
}
|
|
}
|
|
|
|
// Prüfen ob composite_path-Spalte existiert
|
|
$has_composite = false;
|
|
$ccheck = $db->query("SHOW COLUMNS FROM ".$db->prefix()."bericht_page LIKE 'composite_path'");
|
|
if ($ccheck && $db->num_rows($ccheck) > 0) $has_composite = true;
|
|
|
|
$sets = array(
|
|
"fabric_json = ".($fabric !== '' ? "'".$db->escape($fabric)."'" : "NULL"),
|
|
"note = ".($note !== '' ? "'".$db->escape($note)."'" : "NULL"),
|
|
"rotation = ".((int) $rotation),
|
|
);
|
|
if ($composite_relpath !== null && $has_composite) {
|
|
$sets[] = "composite_path = '".$db->escape($composite_relpath)."'";
|
|
}
|
|
|
|
$sql = "UPDATE ".$db->prefix()."bericht_page SET ".implode(', ', $sets)." WHERE rowid = ".((int) $pageid);
|
|
if (!$db->query($sql)) bericht_ajax_fail('DB-Fehler: '.$db->lasterror());
|
|
|
|
bericht_ajax_ok(array('composite_saved' => $composite_relpath !== null));
|