kundenkarte/lib/graph_view.lib.php
data ee4c6688d9 feat(graph): View-Modes pro System, Compound-Node Fixes, Resize-Handles, Admin-Gear
- Ansichtsmodus (tree/graph/both) pro System konfigurierbar
- Admin-Zahnrad-Icon auf Kunden- und Kontakt-Anlagen-Tab
- Compound-Nodes: Alle Nachkommen eines Gebäudes werden umschlossen
- Leitungen/Verbindungen aus der Baumansicht entfernt (nur noch im Graph)
- Resize-Handles für Gebäude-Nodes im Bearbeitungsmodus
- graph_width/graph_height Spalten für persistente Gebäudegrößen
- view_modes Spalte in System-Tabelle
- DB-Migrationen in modKundenKarte

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:35:22 +01:00

163 lines
7.8 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* Gemeinsame Graph-Ansicht Funktionen für anlagen.php und contact_anlagen.php
* Vermeidet doppelten Code für Toolbar, Container, Kontextmenü, Legende
*/
/**
* Graph-spezifische JS/CSS-Dateien zu den Asset-Arrays hinzufügen
*
* @param array $jsFiles Referenz auf JS-Array
* @param array $cssFiles Referenz auf CSS-Array
* @param string $viewMode 'tree' oder 'graph'
*/
function kundenkarte_graph_add_assets(&$jsFiles, &$cssFiles, $viewMode)
{
if ($viewMode === 'graph') {
$jsFiles[] = '/kundenkarte/js/dagre.min.js';
$jsFiles[] = '/kundenkarte/js/cytoscape.min.js';
$jsFiles[] = '/kundenkarte/js/cytoscape-dagre.js';
$jsFiles[] = '/kundenkarte/js/kundenkarte_cytoscape.js?v='.time();
$cssFiles[] = '/kundenkarte/css/kundenkarte_cytoscape.css?v='.time();
} else {
array_unshift($jsFiles, '/kundenkarte/js/pathfinding.min.js');
}
}
/**
* Graph-Toolbar rendern (2 Zeilen: Aktionen + Steuerung)
* Wird UNTER der System-Tab-Borderlinie ausgegeben
*
* @param array $params Konfiguration:
* 'socid' int Kunden-ID
* 'contactid' int Kontakt-ID (0 für Kundenansicht)
* 'systemid' int Aktuelles System
* 'viewMode' string 'tree' oder 'graph'
* 'permissiontoadd' bool Schreibberechtigung
* 'pageUrl' string Aktuelle Seiten-URL ($_SERVER['PHP_SELF'])
*/
function kundenkarte_graph_print_toolbar($params)
{
global $langs;
$socId = (int) ($params['socid'] ?? 0);
$contactId = (int) ($params['contactid'] ?? 0);
$systemId = (int) ($params['systemid'] ?? 0);
$viewMode = $params['viewMode'] ?? 'tree';
$permissiontoadd = !empty($params['permissiontoadd']);
$pageUrl = $params['pageUrl'] ?? $_SERVER['PHP_SELF'];
$allowedViews = $params['allowedViews'] ?? 'both';
// View-Toggle URL: ID-Parameter je nach Kontext
$idParam = ($contactId > 0) ? $contactId : $socId;
$toggleView = ($viewMode === 'graph') ? 'tree' : 'graph';
$toggleUrl = $pageUrl.'?id='.$idParam.'&system='.$systemId.'&view='.$toggleView;
$toggleIcon = ($viewMode === 'graph') ? 'fa-list' : 'fa-sitemap';
$toggleLabel = ($viewMode === 'graph') ? $langs->trans('TreeView') : $langs->trans('GraphView');
// Connection-URL: bei Kontakten wird socid + contactid übergeben
$connUrlParams = 'socid='.$socId;
if ($contactId > 0) {
$connUrlParams .= '&contactid='.$contactId;
}
print '<div class="kundenkarte-graph-toolbar">';
// Zeile 1: Ansicht-Wechsel + Aktionen
print '<div class="kundenkarte-graph-toolbar-row">';
if ($allowedViews === 'both') {
print '<a class="button small" href="'.$toggleUrl.'" title="'.$toggleLabel.'"><i class="fa '.$toggleIcon.'"></i> '.$toggleLabel.'</a>';
}
if ($permissiontoadd) {
print '<a class="button small" href="'.$pageUrl.'?id='.$idParam.'&action=create&system='.$systemId.'"><i class="fa fa-plus"></i> '.$langs->trans('AddElement').'</a>';
print '<a class="button small" href="'.dol_buildpath('/kundenkarte/anlage_connection.php', 1).'?'.$connUrlParams.'&system_id='.$systemId.'&action=create"><i class="fa fa-plug"></i> '.$langs->trans('AddConnection').'</a>';
}
print '</div>';
// Zeile 2: Graph-Steuerung (Anordnen rechts)
print '<div class="kundenkarte-graph-toolbar-row">';
print '<button type="button" class="button small" id="btn-graph-reset-layout" title="Layout zurücksetzen"><i class="fa fa-refresh"></i> Layout</button>';
print '<button type="button" class="button small" id="btn-graph-wheel-zoom" title="Mausrad-Zoom"><i class="fa fa-arrows"></i> Scroll</button>';
print '<button type="button" class="button small" id="btn-graph-zoom-in" title="Vergrößern"><i class="fa fa-search-plus"></i></button>';
print '<button type="button" class="button small" id="btn-graph-zoom-out" title="Verkleinern"><i class="fa fa-search-minus"></i></button>';
print '<button type="button" class="button small" id="btn-graph-fit" title="Einpassen"><i class="fa fa-crosshairs"></i> Fit</button>';
print '<button type="button" class="button small" id="btn-graph-export-png" title="PNG exportieren"><i class="fa fa-download"></i> PNG</button>';
if ($permissiontoadd) {
print '<span class="kundenkarte-graph-toolbar-spacer"></span>';
print '<button type="button" class="button small" id="btn-graph-edit-mode" title="Elemente anordnen"><i class="fa fa-hand-paper-o"></i> Anordnen</button>';
print '<button type="button" class="button small btn-graph-save" id="btn-graph-save-positions" title="Positionen speichern" style="display:none;"><i class="fa fa-check"></i> Speichern</button>';
print '<button type="button" class="button small btn-graph-cancel" id="btn-graph-cancel-edit" title="Abbrechen" style="display:none;"><i class="fa fa-times"></i> Abbrechen</button>';
}
print '</div>';
print '</div>';
}
/**
* Graph-Container, Kontextmenü und Legende rendern
*
* @param array $params Konfiguration:
* 'socid' int Kunden-ID
* 'contactid' int Kontakt-ID (0 für Kundenansicht)
* 'systemid' int Aktuelles System
* 'permissiontoadd' bool Schreibberechtigung
* 'permissiontodelete' bool Löschberechtigung
* 'pageUrl' string Aktuelle Seiten-URL
*/
function kundenkarte_graph_print_container($params)
{
global $langs;
$socId = (int) ($params['socid'] ?? 0);
$contactId = (int) ($params['contactid'] ?? 0);
$systemId = (int) ($params['systemid'] ?? 0);
$permissiontoadd = !empty($params['permissiontoadd']);
$permissiontodelete = !empty($params['permissiontodelete']);
$pageUrl = $params['pageUrl'] ?? $_SERVER['PHP_SELF'];
$graphAjaxUrl = dol_buildpath('/kundenkarte/ajax/graph_data.php', 1);
$graphSaveUrl = dol_buildpath('/kundenkarte/ajax/graph_save_positions.php', 1);
$graphModuleUrl = dol_buildpath('/kundenkarte', 1);
print '<div class="kundenkarte-graph-wrapper">';
// Suchfeld als Overlay
print '<div class="kundenkarte-graph-search-floating">';
print '<input type="text" id="kundenkarte-graph-search" placeholder="'.$langs->trans('SearchPlaceholder').'" autocomplete="off">';
print '</div>';
// Graph-Container mit Data-Attributen für JS-Initialisierung
print '<div id="kundenkarte-graph-container"';
print ' data-ajax-url="'.dol_escape_htmltag($graphAjaxUrl).'"';
print ' data-save-url="'.dol_escape_htmltag($graphSaveUrl).'"';
print ' data-module-url="'.dol_escape_htmltag($graphModuleUrl).'"';
print ' data-socid="'.$socId.'"';
if ($contactId > 0) {
print ' data-contactid="'.$contactId.'"';
}
print ' data-systemid="'.$systemId.'"';
print ' data-can-edit="'.($permissiontoadd ? '1' : '0').'"';
print ' data-can-delete="'.($permissiontodelete ? '1' : '0').'"';
print ' data-page-url="'.dol_escape_htmltag($pageUrl).'"';
print '>';
print '<div class="kundenkarte-graph-loading"><i class="fa fa-spinner fa-spin"></i> '.$langs->trans('GraphLoading').'</div>';
print '</div>';
// Kontextmenü (Rechtsklick auf Node)
print '<div id="kundenkarte-graph-contextmenu" class="kundenkarte-graph-contextmenu" style="display:none;">';
print '<a class="ctx-item ctx-view" data-action="view"><i class="fa fa-eye"></i> '.$langs->trans('View').'</a>';
if ($permissiontoadd) {
print '<a class="ctx-item ctx-add-child" data-action="add-child"><i class="fa fa-plus"></i> '.$langs->trans('AddChild').'</a>';
print '<a class="ctx-item ctx-edit" data-action="edit"><i class="fa fa-edit"></i> '.$langs->trans('Edit').'</a>';
print '<a class="ctx-item ctx-copy" data-action="copy"><i class="fa fa-copy"></i> '.$langs->trans('Copy').'</a>';
}
if ($permissiontodelete) {
print '<a class="ctx-item ctx-delete" data-action="delete"><i class="fa fa-trash"></i> '.$langs->trans('Delete').'</a>';
}
print '</div>';
// Legende - wird dynamisch vom JS befüllt (Kabeltypen mit Farben)
print '<div id="kundenkarte-graph-legend" class="kundenkarte-graph-legend"></div>';
print '</div>'; // End kundenkarte-graph-wrapper
}