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>
332 lines
12 KiB
PHP
Executable file
332 lines
12 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Alles Watt lauft
|
|
*
|
|
* Admin page for managing Medium Types (Kabeltypen)
|
|
*/
|
|
|
|
// Load Dolibarr environment
|
|
$res = 0;
|
|
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
|
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
|
if (!$res) die("Include of main fails");
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
|
dol_include_once('/kundenkarte/class/mediumtype.class.php');
|
|
dol_include_once('/kundenkarte/lib/kundenkarte.lib.php');
|
|
|
|
$langs->loadLangs(array("admin", "kundenkarte@kundenkarte"));
|
|
|
|
// Security check
|
|
if (!$user->admin) {
|
|
accessforbidden();
|
|
}
|
|
|
|
$action = GETPOST('action', 'aZ09');
|
|
$typeId = GETPOSTINT('typeid');
|
|
|
|
$mediumType = new MediumType($db);
|
|
|
|
// Load systems for dropdown
|
|
$systems = array();
|
|
$sql = "SELECT rowid, code, label FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE active = 1 ORDER BY position, label";
|
|
$resql = $db->query($sql);
|
|
if ($resql) {
|
|
while ($obj = $db->fetch_object($resql)) {
|
|
$systems[$obj->rowid] = $obj;
|
|
}
|
|
}
|
|
|
|
$error = 0;
|
|
$message = '';
|
|
|
|
// Actions
|
|
if ($action == 'add' && $user->admin) {
|
|
$mediumType->ref = GETPOST('ref', 'alphanohtml');
|
|
$mediumType->label = GETPOST('label', 'alphanohtml');
|
|
$mediumType->label_short = GETPOST('label_short', 'alphanohtml');
|
|
$mediumType->description = GETPOST('description', 'restricthtml');
|
|
$mediumType->fk_system = GETPOSTINT('fk_system');
|
|
$mediumType->category = GETPOST('category', 'alphanohtml');
|
|
$mediumType->default_spec = GETPOST('default_spec', 'alphanohtml');
|
|
$mediumType->color = GETPOST('color', 'alphanohtml');
|
|
$mediumType->position = GETPOSTINT('position');
|
|
$mediumType->active = GETPOSTINT('active');
|
|
|
|
// Available specs as JSON array
|
|
$specsText = GETPOST('available_specs', 'nohtml');
|
|
if ($specsText) {
|
|
$specsArray = array_map('trim', explode(',', $specsText));
|
|
$mediumType->available_specs = json_encode($specsArray);
|
|
}
|
|
|
|
$result = $mediumType->create($user);
|
|
if ($result > 0) {
|
|
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
|
|
header('Location: '.$_SERVER['PHP_SELF']);
|
|
exit;
|
|
} else {
|
|
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
|
|
$action = 'create';
|
|
}
|
|
}
|
|
|
|
if ($action == 'update' && $user->admin) {
|
|
if ($mediumType->fetch($typeId) > 0) {
|
|
$mediumType->ref = GETPOST('ref', 'alphanohtml');
|
|
$mediumType->label = GETPOST('label', 'alphanohtml');
|
|
$mediumType->label_short = GETPOST('label_short', 'alphanohtml');
|
|
$mediumType->description = GETPOST('description', 'restricthtml');
|
|
$mediumType->fk_system = GETPOSTINT('fk_system');
|
|
$mediumType->category = GETPOST('category', 'alphanohtml');
|
|
$mediumType->default_spec = GETPOST('default_spec', 'alphanohtml');
|
|
$mediumType->color = GETPOST('color', 'alphanohtml');
|
|
$mediumType->position = GETPOSTINT('position');
|
|
$mediumType->active = GETPOSTINT('active');
|
|
|
|
$specsText = GETPOST('available_specs', 'nohtml');
|
|
if ($specsText) {
|
|
$specsArray = array_map('trim', explode(',', $specsText));
|
|
$mediumType->available_specs = json_encode($specsArray);
|
|
} else {
|
|
$mediumType->available_specs = '';
|
|
}
|
|
|
|
$result = $mediumType->update($user);
|
|
if ($result > 0) {
|
|
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
|
|
header('Location: '.$_SERVER['PHP_SELF']);
|
|
exit;
|
|
} else {
|
|
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
|
|
$action = 'edit';
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($action == 'confirm_delete' && GETPOST('confirm') == 'yes' && $user->admin) {
|
|
if ($mediumType->fetch($typeId) > 0) {
|
|
$result = $mediumType->delete($user);
|
|
if ($result > 0) {
|
|
setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($mediumType->error, $mediumType->errors, 'errors');
|
|
}
|
|
}
|
|
header('Location: '.$_SERVER['PHP_SELF']);
|
|
exit;
|
|
}
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
$title = $langs->trans('MediumTypes');
|
|
llxHeader('', $title);
|
|
|
|
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
|
|
|
|
print load_fiche_titre($title, $linkback, 'title_setup');
|
|
|
|
// Admin tabs
|
|
$head = kundenkarteAdminPrepareHead();
|
|
print dol_get_fiche_head($head, 'medium_types', $langs->trans('KundenKarte'), -1, 'kundenkarte@kundenkarte');
|
|
|
|
// Delete confirmation
|
|
if ($action == 'delete') {
|
|
if ($mediumType->fetch($typeId) > 0) {
|
|
print $form->formconfirm(
|
|
$_SERVER['PHP_SELF'].'?typeid='.$typeId,
|
|
$langs->trans('DeleteMediumType'),
|
|
$langs->trans('ConfirmDeleteMediumType', $mediumType->label),
|
|
'confirm_delete',
|
|
'',
|
|
0,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
|
|
// Add/Edit form
|
|
if (in_array($action, array('create', 'edit'))) {
|
|
if ($action == 'edit' && $typeId > 0) {
|
|
$mediumType->fetch($typeId);
|
|
}
|
|
|
|
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="'.($action == 'edit' ? 'update' : 'add').'">';
|
|
if ($action == 'edit') {
|
|
print '<input type="hidden" name="typeid" value="'.$typeId.'">';
|
|
}
|
|
|
|
print '<table class="border centpercent">';
|
|
|
|
// Ref
|
|
print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td>';
|
|
print '<td><input type="text" name="ref" value="'.dol_escape_htmltag($mediumType->ref ?: GETPOST('ref')).'" size="20" maxlength="50" required></td></tr>';
|
|
|
|
// Label
|
|
print '<tr><td class="fieldrequired">'.$langs->trans('Label').'</td>';
|
|
print '<td><input type="text" name="label" value="'.dol_escape_htmltag($mediumType->label ?: GETPOST('label')).'" size="40" maxlength="128" required></td></tr>';
|
|
|
|
// Label short
|
|
print '<tr><td>'.$langs->trans('LabelShort').'</td>';
|
|
print '<td><input type="text" name="label_short" value="'.dol_escape_htmltag($mediumType->label_short ?: GETPOST('label_short')).'" size="20" maxlength="32"></td></tr>';
|
|
|
|
// System
|
|
print '<tr><td>'.$langs->trans('System').'</td>';
|
|
print '<td><select name="fk_system" class="flat">';
|
|
print '<option value="0">'.$langs->trans('AllSystems').'</option>';
|
|
foreach ($systems as $sys) {
|
|
$selected = ($mediumType->fk_system == $sys->rowid) ? ' selected' : '';
|
|
print '<option value="'.$sys->rowid.'"'.$selected.'>'.dol_escape_htmltag($sys->label).'</option>';
|
|
}
|
|
print '</select></td></tr>';
|
|
|
|
// Category
|
|
print '<tr><td>'.$langs->trans('Category').'</td>';
|
|
print '<td><select name="category" class="flat">';
|
|
$categories = MediumType::getCategoryOptions();
|
|
foreach ($categories as $code => $label) {
|
|
$selected = ($mediumType->category == $code) ? ' selected' : '';
|
|
print '<option value="'.$code.'"'.$selected.'>'.dol_escape_htmltag($label).'</option>';
|
|
}
|
|
print '</select></td></tr>';
|
|
|
|
// Default spec
|
|
print '<tr><td>'.$langs->trans('DefaultSpec').'</td>';
|
|
print '<td><input type="text" name="default_spec" value="'.dol_escape_htmltag($mediumType->default_spec ?: GETPOST('default_spec')).'" size="20" maxlength="100">';
|
|
print '<br><span class="opacitymedium">'.$langs->trans('DefaultSpecHelp').'</span></td></tr>';
|
|
|
|
// Available specs
|
|
$specsText = '';
|
|
if ($mediumType->available_specs) {
|
|
$specsArray = json_decode($mediumType->available_specs, true);
|
|
if (is_array($specsArray)) {
|
|
$specsText = implode(', ', $specsArray);
|
|
}
|
|
}
|
|
print '<tr><td>'.$langs->trans('AvailableSpecs').'</td>';
|
|
print '<td><input type="text" name="available_specs" value="'.dol_escape_htmltag($specsText ?: GETPOST('available_specs')).'" size="60">';
|
|
print '<br><span class="opacitymedium">'.$langs->trans('AvailableSpecsHelp').'</span></td></tr>';
|
|
|
|
// Color
|
|
print '<tr><td>'.$langs->trans('Color').'</td>';
|
|
print '<td><input type="color" name="color" value="'.dol_escape_htmltag($mediumType->color ?: '#666666').'" style="width:50px;height:30px;">';
|
|
print ' <input type="text" name="color_text" value="'.dol_escape_htmltag($mediumType->color ?: '#666666').'" size="10" onchange="this.form.color.value=this.value" placeholder="#RRGGBB"></td></tr>';
|
|
|
|
// Position
|
|
print '<tr><td>'.$langs->trans('Position').'</td>';
|
|
print '<td><input type="number" name="position" value="'.((int) ($mediumType->position ?: GETPOSTINT('position'))).'" min="0" max="999"></td></tr>';
|
|
|
|
// Status
|
|
print '<tr><td>'.$langs->trans('Status').'</td>';
|
|
print '<td><select name="active" class="flat">';
|
|
$activeValue = ($action == 'edit') ? $mediumType->active : 1;
|
|
print '<option value="1"'.($activeValue == 1 ? ' selected' : '').'>'.$langs->trans('Enabled').'</option>';
|
|
print '<option value="0"'.($activeValue == 0 ? ' selected' : '').'>'.$langs->trans('Disabled').'</option>';
|
|
print '</select></td></tr>';
|
|
|
|
// Description
|
|
print '<tr><td>'.$langs->trans('Description').'</td>';
|
|
print '<td><textarea name="description" rows="3" cols="60">'.dol_escape_htmltag($mediumType->description ?: GETPOST('description')).'</textarea></td></tr>';
|
|
|
|
print '</table>';
|
|
|
|
print '<div class="center" style="margin-top:15px;">';
|
|
print '<input type="submit" class="button button-save" value="'.$langs->trans('Save').'">';
|
|
print ' <a class="button button-cancel" href="'.$_SERVER['PHP_SELF'].'">'.$langs->trans('Cancel').'</a>';
|
|
print '</div>';
|
|
|
|
print '</form>';
|
|
|
|
} else {
|
|
// List view
|
|
|
|
// Button to add
|
|
print '<div class="tabsAction">';
|
|
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?action=create">'.$langs->trans('AddMediumType').'</a>';
|
|
print '</div>';
|
|
|
|
// Filter by category
|
|
$filterCategory = GETPOST('filter_category', 'alphanohtml');
|
|
print '<form method="GET" action="'.$_SERVER['PHP_SELF'].'" style="margin-bottom:15px;">';
|
|
print '<label>'.$langs->trans('FilterByCategory').': </label>';
|
|
print '<select name="filter_category" class="flat" onchange="this.form.submit()">';
|
|
print '<option value="">'.$langs->trans('All').'</option>';
|
|
$categories = MediumType::getCategoryOptions();
|
|
foreach ($categories as $code => $label) {
|
|
$selected = ($filterCategory == $code) ? ' selected' : '';
|
|
print '<option value="'.$code.'"'.$selected.'>'.dol_escape_htmltag($label).'</option>';
|
|
}
|
|
print '</select>';
|
|
print '</form>';
|
|
|
|
// List
|
|
$allTypes = $mediumType->fetchAllBySystem(0, 0);
|
|
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th>'.$langs->trans('Ref').'</th>';
|
|
print '<th>'.$langs->trans('Label').'</th>';
|
|
print '<th>'.$langs->trans('Category').'</th>';
|
|
print '<th>'.$langs->trans('System').'</th>';
|
|
print '<th>'.$langs->trans('DefaultSpec').'</th>';
|
|
print '<th class="center">'.$langs->trans('Color').'</th>';
|
|
print '<th class="center">'.$langs->trans('Position').'</th>';
|
|
print '<th class="center">'.$langs->trans('Status').'</th>';
|
|
print '<th class="center">'.$langs->trans('Actions').'</th>';
|
|
print '</tr>';
|
|
|
|
if (empty($allTypes)) {
|
|
print '<tr><td colspan="9" class="opacitymedium">'.$langs->trans('NoRecords').'</td></tr>';
|
|
} else {
|
|
$i = 0;
|
|
foreach ($allTypes as $t) {
|
|
// Filter
|
|
if ($filterCategory && $t->category != $filterCategory) continue;
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td><strong>'.dol_escape_htmltag($t->ref).'</strong></td>';
|
|
print '<td>'.dol_escape_htmltag($t->label);
|
|
if ($t->label_short) print ' <span class="opacitymedium">('.dol_escape_htmltag($t->label_short).')</span>';
|
|
print '</td>';
|
|
print '<td>'.dol_escape_htmltag($t->getCategoryLabel()).'</td>';
|
|
print '<td>';
|
|
if ($t->fk_system > 0 && $t->system_label) {
|
|
print dol_escape_htmltag($t->system_label);
|
|
} else {
|
|
print '<em>'.$langs->trans('AllSystems').'</em>';
|
|
}
|
|
print '</td>';
|
|
print '<td>'.dol_escape_htmltag($t->default_spec).'</td>';
|
|
print '<td class="center"><span style="display:inline-block;width:20px;height:20px;background:'.dol_escape_htmltag($t->color ?: '#ccc').';border:1px solid #999;border-radius:3px;"></span></td>';
|
|
print '<td class="center">'.$t->position.'</td>';
|
|
print '<td class="center">';
|
|
print $t->active ? '<span class="badge badge-status4">'.$langs->trans('Enabled').'</span>' : '<span class="badge badge-status5">'.$langs->trans('Disabled').'</span>';
|
|
print '</td>';
|
|
print '<td class="center nowraponall">';
|
|
print '<a href="'.$_SERVER['PHP_SELF'].'?action=edit&typeid='.$t->id.'"><i class="fa fa-edit" title="'.$langs->trans('Edit').'"></i></a>';
|
|
if (!$t->is_system) {
|
|
print ' <a href="'.$_SERVER['PHP_SELF'].'?action=delete&typeid='.$t->id.'"><i class="fa fa-trash" style="color:#c00;" title="'.$langs->trans('Delete').'"></i></a>';
|
|
}
|
|
print '</td>';
|
|
print '</tr>';
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
print '</table>';
|
|
}
|
|
|
|
print dol_get_fiche_end();
|
|
|
|
// JavaScript for color picker sync
|
|
print '<script>
|
|
document.querySelector("input[name=color]").addEventListener("input", function() {
|
|
document.querySelector("input[name=color_text]").value = this.value;
|
|
});
|
|
</script>';
|
|
|
|
llxFooter();
|
|
$db->close();
|