kundenkarte/lib/kundenkarte.lib.php
data 844e6060c6 feat(pwa): Offline-fähige Progressive Web App für Elektriker
PWA Mobile App für Schaltschrank-Dokumentation vor Ort:
- Token-basierte Authentifizierung (15 Tage gültig)
- Kundensuche mit Offline-Cache
- Anlagen-Auswahl und Offline-Laden
- Felder/Hutschienen/Automaten erfassen
- Automatische Synchronisierung wenn wieder online
- Installierbar auf dem Smartphone Home Screen
- Touch-optimiertes Dark Mode Design
- Quick-Select für Automaten-Werte (B16, C32, etc.)

Schaltplan-Editor Verbesserungen:
- Block Hover-Tooltip mit show_in_hover Feldern
- Produktinfo mit Icon im Tooltip
- Position und Breite in TE

Neue Dateien:
- pwa.php, pwa_auth.php - PWA Einstieg & Auth
- ajax/pwa_api.php - PWA AJAX API
- js/pwa.js, css/pwa.css - PWA App & Styles
- sw.js, manifest.json - Service Worker & Manifest
- img/pwa-icon-192.png, img/pwa-icon-512.png

Version: 5.2.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 15:27:06 +01:00

248 lines
7.5 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file kundenkarte/lib/kundenkarte.lib.php
* \ingroup kundenkarte
* \brief Library files with common functions for KundenKarte
*/
/**
* Prepare admin pages header
*
* @return array<array{string,string,string}>
*/
function kundenkarteAdminPrepareHead()
{
global $langs, $conf;
// global $db;
// $extrafields = new ExtraFields($db);
// $extrafields->fetch_name_optionals_label('myobject');
$langs->load("kundenkarte@kundenkarte");
$h = 0;
$head = array();
$head[$h][0] = dol_buildpath("/kundenkarte/admin/setup.php", 1);
$head[$h][1] = $langs->trans("Settings");
$head[$h][2] = 'settings';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/anlage_systems.php", 1);
$head[$h][1] = $langs->trans("AnlagenSystems");
$head[$h][2] = 'systems';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/anlage_types.php", 1);
$head[$h][1] = $langs->trans("AnlagenTypes");
$head[$h][2] = 'types';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/equipment_types.php", 1);
$head[$h][1] = $langs->trans("EquipmentTypes");
$head[$h][2] = 'equipment_types';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/busbar_types.php", 1);
$head[$h][1] = $langs->trans("BusbarTypes");
$head[$h][2] = 'busbar_types';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/medium_types.php", 1);
$head[$h][1] = $langs->trans("MediumTypes");
$head[$h][2] = 'medium_types';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/building_types.php", 1);
$head[$h][1] = $langs->trans("BuildingTypes");
$head[$h][2] = 'building_types';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/backup.php", 1);
$head[$h][1] = $langs->trans("BackupRestore");
$head[$h][2] = 'backup';
$h++;
/*
$head[$h][0] = dol_buildpath("/kundenkarte/admin/myobject_extrafields.php", 1);
$head[$h][1] = $langs->trans("ExtraFields");
$nbExtrafields = (isset($extrafields->attributes['myobject']['label']) && is_countable($extrafields->attributes['myobject']['label'])) ? count($extrafields->attributes['myobject']['label']) : 0;
if ($nbExtrafields > 0) {
$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbExtrafields . '</span>';
}
$head[$h][2] = 'myobject_extrafields';
$h++;
$head[$h][0] = dol_buildpath("/kundenkarte/admin/myobjectline_extrafields.php", 1);
$head[$h][1] = $langs->trans("ExtraFieldsLines");
$nbExtrafields = (isset($extrafields->attributes['myobjectline']['label']) && is_countable($extrafields->attributes['myobjectline']['label'])) ? count($extrafields->attributes['myobject']['label']) : 0;
if ($nbExtrafields > 0) {
$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbExtrafields . '</span>';
}
$head[$h][2] = 'myobject_extrafieldsline';
$h++;
*/
$head[$h][0] = dol_buildpath("/kundenkarte/admin/about.php", 1);
$head[$h][1] = $langs->trans("About");
$head[$h][2] = 'about';
$h++;
// Show more tabs from modules
// Entries must be declared in modules descriptor with line
//$this->tabs = array(
// 'entity:+tabname:Title:@kundenkarte:/kundenkarte/mypage.php?id=__ID__'
//); // to add new tab
//$this->tabs = array(
// 'entity:-tabname:Title:@kundenkarte:/kundenkarte/mypage.php?id=__ID__'
//); // to remove a tab
complete_head_from_modules($conf, $langs, null, $head, $h, 'kundenkarte@kundenkarte');
complete_head_from_modules($conf, $langs, null, $head, $h, 'kundenkarte@kundenkarte', 'remove');
return $head;
}
/**
* Render an icon - either Font Awesome or custom image
*
* @param string $picto Icon identifier (fa-xxx or img:url)
* @param string $alt Alt text for images
* @param string $style Additional inline style
* @return string HTML for the icon
*/
function kundenkarte_render_icon($picto, $alt = '', $style = '')
{
if (empty($picto)) {
return '<i class="fa fa-cube"'.($style ? ' style="'.$style.'"' : '').'></i>';
}
// Check if it's a custom image (starts with img:)
if (strpos($picto, 'img:') === 0) {
$url = substr($picto, 4); // Remove 'img:' prefix
$styleAttr = 'max-width:20px;max-height:20px;vertical-align:middle;'.($style ? $style : '');
return '<img src="'.dol_escape_htmltag($url).'" alt="'.dol_escape_htmltag($alt).'" style="'.$styleAttr.'">';
}
// Font Awesome icon
return '<i class="fa '.dol_escape_htmltag($picto).'"'.($style ? ' style="'.$style.'"' : '').'></i>';
}
/**
* Get icon for a field based on field code or type
*
* @param string $fieldCode Field code
* @param string $fieldType Field type
* @return string Font Awesome icon class
*/
function kundenkarte_get_field_icon($fieldCode, $fieldType = '')
{
// Map common field codes to icons
$codeIcons = array(
'standort' => 'fa-map-marker',
'location' => 'fa-map-marker',
'ort' => 'fa-map-marker',
'raum' => 'fa-door-open',
'room' => 'fa-door-open',
'zimmer' => 'fa-door-open',
'etage' => 'fa-layer-group',
'floor' => 'fa-layer-group',
'stockwerk' => 'fa-layer-group',
'gebaeude' => 'fa-building',
'building' => 'fa-building',
'adresse' => 'fa-home',
'address' => 'fa-home',
'hersteller' => 'fa-industry',
'manufacturer' => 'fa-industry',
'modell' => 'fa-tag',
'model' => 'fa-tag',
'seriennummer' => 'fa-barcode',
'serial' => 'fa-barcode',
'leistung' => 'fa-bolt',
'power' => 'fa-bolt',
'spannung' => 'fa-plug',
'voltage' => 'fa-plug',
'strom' => 'fa-bolt',
'current' => 'fa-bolt',
'datum' => 'fa-calendar',
'date' => 'fa-calendar',
'installation' => 'fa-wrench',
'wartung' => 'fa-tools',
'maintenance' => 'fa-tools',
'ip' => 'fa-network-wired',
'ip_adresse' => 'fa-network-wired',
'mac' => 'fa-ethernet',
'telefon' => 'fa-phone',
'phone' => 'fa-phone',
'notiz' => 'fa-sticky-note',
'note' => 'fa-sticky-note',
'bemerkung' => 'fa-comment',
'comment' => 'fa-comment',
);
// Check field code (lowercase)
$codeLower = strtolower($fieldCode);
foreach ($codeIcons as $key => $icon) {
if (strpos($codeLower, $key) !== false) {
return $icon;
}
}
// Fallback based on field type
$typeIcons = array(
'date' => 'fa-calendar',
'number' => 'fa-hashtag',
'textarea' => 'fa-align-left',
'select' => 'fa-list',
'checkbox' => 'fa-check-square',
);
if (isset($typeIcons[$fieldType])) {
return $typeIcons[$fieldType];
}
// Default icon
return 'fa-info-circle';
}
/**
* Adjust a hex color by a percentage
*
* @param string $hex Hex color (e.g., #2a4a5e)
* @param int $percent Percentage to adjust (-100 to 100, negative = darker)
* @return string Adjusted hex color
*/
function kundenkarte_adjust_color($hex, $percent)
{
// Remove # if present
$hex = ltrim($hex, '#');
// Parse RGB values
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
// Adjust each component
$r = max(0, min(255, $r + $percent));
$g = max(0, min(255, $g + $percent));
$b = max(0, min(255, $b + $percent));
// Return as hex
return sprintf('#%02x%02x%02x', $r, $g, $b);
}