Compare commits
No commits in common. "192cdad8e08703a437b52bea527e2b36da309af0" and "2b3514f762d6c84ae67c0f8ec74f90127305bd07" have entirely different histories.
192cdad8e0
...
2b3514f762
3 changed files with 43 additions and 177 deletions
|
|
@ -102,13 +102,10 @@ Sie können beim Kunden (unter **Kunden > Kundenkarte**) eine Standard-Leistung
|
|||
### Version 1.2.0
|
||||
- **Leistungsposition pro Arbeitszeit**: Jede Arbeitszeit kann einer eigenen Leistungsposition (Dienstleistung) zugeordnet werden
|
||||
- **Mobile-optimierte Ansicht**: Responsive CSS für Touch-Geräte (Smartphones/Tablets)
|
||||
- Kompakte Tabellen mit horizontalem Scrollen bei Bedarf
|
||||
- Größere Touch-Targets für Buttons und Icons
|
||||
- Automatisches Karten-Layout bei Bildschirmbreite < 768px
|
||||
- Größere Touch-Buttons (44px+)
|
||||
- Kein horizontales Scrollen mehr
|
||||
- Optimierte Eingabefelder (Font 16px, kein iOS-Zoom)
|
||||
- Beschreibungsfelder auf separater Zeile für bessere Bedienbarkeit
|
||||
- Grund/Beschreibung wird klein unter dem Produktnamen angezeigt
|
||||
- Action-Buttons sticky am unteren Bildschirmrand
|
||||
- Dark Mode Support (kompatibel mit Dolibarr Themes)
|
||||
- **Erweiterte Lieferauflistung**: Tracking-Tab zeigt jetzt auch Leistungen gruppiert nach Leistungsposition
|
||||
- **Verbesserte Tab-Navigation**: Einheitliche Tabs auf Auftrags- und Stundenzettel-Ebene
|
||||
- **Layout-Verbesserungen**: Konsistente Spaltenbreiten und Ausrichtung in allen Tabellen
|
||||
|
|
|
|||
69
card.php
69
card.php
|
|
@ -946,7 +946,7 @@ elseif ($object->id > 0) {
|
|||
print '<th>'.$langs->trans("LeistungTimeEnd").'</th>';
|
||||
print '<th class="center">'.$langs->trans("Duration").'</th>';
|
||||
print '<th>'.$langs->trans("DefaultService").'</th>';
|
||||
print '<th class="mobile-hide">'.$langs->trans("Description").'</th>';
|
||||
print '<th>'.$langs->trans("Description").'</th>';
|
||||
if ($object->status == Stundenzettel::STATUS_DRAFT && $permissiontoadd) {
|
||||
print '<th class="center" width="40"></th>'; // Edit
|
||||
print '<th class="center" width="40"></th>'; // Delete
|
||||
|
|
@ -1009,13 +1009,8 @@ elseif ($object->id > 0) {
|
|||
} else {
|
||||
print '<span class="opacitymedium">'.$langs->trans("NotSet").'</span>';
|
||||
}
|
||||
// Mobile: Beschreibung unter Leistungsposition anzeigen
|
||||
if (!empty($leistung->description)) {
|
||||
print '<div class="mobile-inline-desc"><small class="opacitymedium">'.dol_trunc(strip_tags($leistung->description), 60).'</small></div>';
|
||||
}
|
||||
print '</td>';
|
||||
// Beschreibung (auf Mobile ausgeblendet)
|
||||
print '<td class="mobile-hide">'.dol_htmlentitiesbr($leistung->description).'</td>';
|
||||
print '<td>'.dol_htmlentitiesbr($leistung->description).'</td>';
|
||||
if ($object->status == Stundenzettel::STATUS_DRAFT && $permissiontoadd) {
|
||||
// Edit Button
|
||||
print '<td class="center">';
|
||||
|
|
@ -1086,9 +1081,9 @@ elseif ($object->id > 0) {
|
|||
$form->select_produits($defaultServiceId, 'fk_product', 1, 0, 0, -1, 2, '', 0, array(), 0, '1', 0, 'maxwidth200');
|
||||
print '</td>';
|
||||
|
||||
// Beschreibung (Desktop: in Zeile, Mobile: ausgeblendet)
|
||||
print '<td class="mobile-hide">';
|
||||
print '<textarea name="leistung_description" class="flat" rows="3" style="width: 200px; resize: vertical;" placeholder="'.$langs->trans("Description").'"></textarea>';
|
||||
// Beschreibung (Tagesbeschreibung - größeres Textarea, 5 Zeilen)
|
||||
print '<td>';
|
||||
print '<textarea name="leistung_description" class="flat" rows="5" style="width: 300px; resize: vertical;" placeholder="'.$langs->trans("Description").'"></textarea>';
|
||||
print '</td>';
|
||||
|
||||
// Action (colspan=2 für beide Button-Spalten)
|
||||
|
|
@ -1098,13 +1093,6 @@ elseif ($object->id > 0) {
|
|||
|
||||
print '</form>';
|
||||
print '</tr>';
|
||||
|
||||
// Mobile: Beschreibung in separater Zeile
|
||||
print '<tr class="oddeven mobile-description-row">';
|
||||
print '<td colspan="8">';
|
||||
print '<textarea name="leistung_description" form="form_leistung" class="flat" rows="3" style="width: 100%; resize: vertical;" placeholder="'.$langs->trans("Description").'"></textarea>';
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
|
||||
// Summenzeile anzeigen
|
||||
|
|
@ -1344,7 +1332,7 @@ elseif ($object->id > 0) {
|
|||
print '<tr class="liste_titre">';
|
||||
print '<th>'.$langs->trans("Product").'</th>';
|
||||
print '<th class="center" style="width:80px;">'.$langs->trans("Qty").'</th>';
|
||||
print '<th class="mobile-hide" style="width:200px;">'.$langs->trans("Reason").'</th>';
|
||||
print '<th style="width:200px;">'.$langs->trans("Reason").'</th>';
|
||||
print '<th class="center" style="width:40px;"></th>'; // Save
|
||||
print '<th class="center" style="width:40px;"></th>'; // Delete
|
||||
print '</tr>';
|
||||
|
|
@ -1377,10 +1365,6 @@ elseif ($object->id > 0) {
|
|||
print '<span class="opacitymedium">'.$displayText.'</span>';
|
||||
}
|
||||
print ' <span class="badge badge-secondary">'.$langs->trans("Entfaellt").'</span>';
|
||||
// Mobile: Grund unter Produktname anzeigen
|
||||
if (!empty($prod->description)) {
|
||||
print '<div class="mobile-inline-desc"><small class="opacitymedium">'.dol_trunc(strip_tags($prod->description), 50).'</small></div>';
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
// Menge
|
||||
|
|
@ -1393,8 +1377,8 @@ elseif ($object->id > 0) {
|
|||
print '</form>';
|
||||
print '</td>';
|
||||
|
||||
// Grund/Beschreibung (auf Mobile ausgeblendet)
|
||||
print '<td class="mobile-hide" style="width:200px;">';
|
||||
// Grund/Beschreibung
|
||||
print '<td style="width:200px;">';
|
||||
if (!empty($prod->description)) {
|
||||
print dol_htmlentitiesbr($prod->description);
|
||||
} else {
|
||||
|
|
@ -1464,7 +1448,7 @@ elseif ($object->id > 0) {
|
|||
print '</tr>';
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&tab=products" id="form_entfaellt">';
|
||||
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&tab=products">';
|
||||
print '<input type="hidden" name="token" value="'.newToken().'">';
|
||||
print '<input type="hidden" name="action" value="add_entfaellt">';
|
||||
|
||||
|
|
@ -1550,8 +1534,8 @@ elseif ($object->id > 0) {
|
|||
print '<input type="number" name="entfaellt_qty" id="entfaellt_qty_input" class="flat" style="width:70px; text-align:center;" value="1" min="1">';
|
||||
print '</td>';
|
||||
|
||||
// Grund (Desktop: in Zeile, Mobile: ausgeblendet)
|
||||
print '<td class="mobile-hide" style="width:200px;">';
|
||||
// Grund
|
||||
print '<td style="width:200px;">';
|
||||
print '<input type="text" name="entfaellt_description" class="flat" style="width:100%;" placeholder="'.$langs->trans("Reason").'">';
|
||||
print '</td>';
|
||||
|
||||
|
|
@ -1565,13 +1549,6 @@ elseif ($object->id > 0) {
|
|||
print '</form>';
|
||||
print '</tr>';
|
||||
|
||||
// Mobile: Grund in separater Zeile
|
||||
print '<tr class="oddeven mobile-description-row">';
|
||||
print '<td colspan="5">';
|
||||
print '<input type="text" name="entfaellt_description" form="form_entfaellt" class="flat" style="width:100%;" placeholder="'.$langs->trans("Reason").'">';
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
|
||||
// JavaScript für dynamische Max-Menge
|
||||
print '<script>
|
||||
function updateMaxQty(selectElement) {
|
||||
|
|
@ -1608,7 +1585,7 @@ elseif ($object->id > 0) {
|
|||
print '<tr class="liste_titre">';
|
||||
print '<th>'.$langs->trans("Product").'</th>';
|
||||
print '<th class="center" style="width:80px;">'.$langs->trans("Qty").'</th>';
|
||||
print '<th class="mobile-hide" style="width:200px;">'.$langs->trans("Reason").'</th>';
|
||||
print '<th style="width:200px;">'.$langs->trans("Reason").'</th>';
|
||||
print '<th class="center" style="width:40px;"></th>'; // Save
|
||||
print '<th class="center" style="width:40px;"></th>'; // Delete
|
||||
print '</tr>';
|
||||
|
|
@ -1643,11 +1620,6 @@ elseif ($object->id > 0) {
|
|||
print '<span class="opacitymedium">'.$displayText.'</span>';
|
||||
}
|
||||
print ' <span class="badge badge-warning">'.$langs->trans("Mehraufwand").'</span>';
|
||||
// Mobile: Grund unter Produktname anzeigen
|
||||
$reason = ($prod->fk_product > 0) ? $prod->description : '';
|
||||
if (!empty($reason)) {
|
||||
print '<div class="mobile-inline-desc"><small class="opacitymedium">'.dol_trunc(strip_tags($reason), 50).'</small></div>';
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
// Menge (qty_done) - editierbar
|
||||
|
|
@ -1663,8 +1635,8 @@ elseif ($object->id > 0) {
|
|||
}
|
||||
print '</td>';
|
||||
|
||||
// Grund (auf Mobile ausgeblendet, nur wenn Produkt gesetzt)
|
||||
print '<td class="mobile-hide" style="width:200px;">';
|
||||
// Grund (nur wenn Produkt gesetzt, sonst ist description der Produktname)
|
||||
print '<td style="width:200px;">';
|
||||
if ($object->status == Stundenzettel::STATUS_DRAFT && $permissiontoadd) {
|
||||
// Grund nur anzeigen/editieren wenn ein Produkt gewählt wurde
|
||||
$reason = ($prod->fk_product > 0) ? $prod->description : '';
|
||||
|
|
@ -1708,7 +1680,7 @@ elseif ($object->id > 0) {
|
|||
print '</tr>';
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&tab=products" id="form_mehraufwand">';
|
||||
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&tab=products">';
|
||||
print '<input type="hidden" name="token" value="'.newToken().'">';
|
||||
print '<input type="hidden" name="action" value="add_mehraufwand">';
|
||||
|
||||
|
|
@ -1724,8 +1696,8 @@ elseif ($object->id > 0) {
|
|||
print '<input type="number" name="mehraufwand_qty" class="flat" style="width:70px; text-align:center;" value="1" min="1">';
|
||||
print '</td>';
|
||||
|
||||
// Grund (Desktop: in Zeile, Mobile: ausgeblendet)
|
||||
print '<td class="mobile-hide" style="width:200px;">';
|
||||
// Grund
|
||||
print '<td style="width:200px;">';
|
||||
print '<input type="text" name="mehraufwand_reason" class="flat" style="width:100%;" placeholder="'.$langs->trans("Reason").'">';
|
||||
print '</td>';
|
||||
|
||||
|
|
@ -1738,13 +1710,6 @@ elseif ($object->id > 0) {
|
|||
|
||||
print '</form>';
|
||||
print '</tr>';
|
||||
|
||||
// Mobile: Grund in separater Zeile
|
||||
print '<tr class="oddeven mobile-description-row">';
|
||||
print '<td colspan="5">';
|
||||
print '<input type="text" name="mehraufwand_reason" form="form_mehraufwand" class="flat" style="width:100%;" placeholder="'.$langs->trans("Reason").'">';
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
|
||||
print '</table>';
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
/**
|
||||
* Stundenzettel Mobile CSS
|
||||
* Responsive Styles für Touch-Geräte
|
||||
* Version 1.2.1
|
||||
* Version 1.2.0
|
||||
*/
|
||||
|
||||
/* ============================================
|
||||
DESKTOP: Mobile-Elemente ausblenden
|
||||
============================================ */
|
||||
.mod-stundenzettel .mobile-description-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mod-stundenzettel .mobile-inline-desc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
MOBILE STYLES (max-width: 768px)
|
||||
============================================ */
|
||||
|
|
@ -89,10 +78,10 @@
|
|||
padding: 8px 4px !important;
|
||||
}
|
||||
|
||||
/* Zeit-Inputs kompakter */
|
||||
/* Zeit-Inputs */
|
||||
.mod-stundenzettel input[type="time"] {
|
||||
width: 70px !important;
|
||||
padding: 6px 4px !important;
|
||||
width: 80px !important;
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
||||
/* Textarea volle Breite */
|
||||
|
|
@ -109,7 +98,7 @@
|
|||
|
||||
.mod-stundenzettel select.minwidth200,
|
||||
.mod-stundenzettel select.minwidth300 {
|
||||
min-width: 120px !important;
|
||||
min-width: 150px !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
|
|
@ -120,10 +109,10 @@
|
|||
/* Icons größer und mit Padding für Touch */
|
||||
.mod-stundenzettel td .fas,
|
||||
.mod-stundenzettel td .far {
|
||||
font-size: 1.2em;
|
||||
padding: 6px;
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
font-size: 1.3em;
|
||||
padding: 8px;
|
||||
min-width: 35px;
|
||||
min-height: 35px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -136,35 +125,31 @@
|
|||
}
|
||||
|
||||
/* ============================================
|
||||
TABS - Kompakter und horizontal scrollbar
|
||||
TABS - Kompakter
|
||||
============================================ */
|
||||
.mod-stundenzettel .tabs {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.mod-stundenzettel .tabsElem a {
|
||||
padding: 8px 10px !important;
|
||||
font-size: 12px !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Tabs umbrechen wenn nötig */
|
||||
.mod-stundenzettel .tabs {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SECTION-TITEL
|
||||
============================================ */
|
||||
.mod-stundenzettel h3 {
|
||||
font-size: 15px;
|
||||
font-size: 16px;
|
||||
padding: 8px 10px;
|
||||
margin: 10px 0 6px 0;
|
||||
margin: 12px 0 8px 0;
|
||||
}
|
||||
|
||||
/* Abschnitts-Header in Tabellen */
|
||||
.mod-stundenzettel tr.liste_titre th[colspan] {
|
||||
font-size: 13px;
|
||||
padding: 8px 6px !important;
|
||||
font-size: 14px;
|
||||
padding: 10px 8px !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
|
@ -175,19 +160,14 @@
|
|||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 10px 5px;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: var(--colorbackbody, inherit);
|
||||
z-index: 100;
|
||||
box-shadow: 0 -2px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.mod-stundenzettel .tabsAction a.butAction,
|
||||
.mod-stundenzettel .tabsAction a.butActionDelete {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
text-align: center;
|
||||
padding: 14px 10px !important;
|
||||
font-size: 14px !important;
|
||||
padding: 12px 8px !important;
|
||||
font-size: 13px !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
|
@ -195,16 +175,11 @@
|
|||
BANNER/HEADER - Kompakter
|
||||
============================================ */
|
||||
.mod-stundenzettel .arearef {
|
||||
padding: 6px !important;
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
||||
.mod-stundenzettel .refid {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Banner-Tabelle kompakter */
|
||||
.mod-stundenzettel .refidno {
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
|
@ -220,7 +195,6 @@
|
|||
|
||||
.mod-stundenzettel .select2-selection__rendered {
|
||||
line-height: 38px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
|
@ -258,59 +232,6 @@
|
|||
.mod-stundenzettel tr.liste_total td {
|
||||
font-size: 13px;
|
||||
padding: 8px 4px !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
LEISTUNGEN TABELLE - Spalten optimieren
|
||||
============================================ */
|
||||
/* Beschreibungs-Spalte kompakter (Wörter umbrechen) */
|
||||
.mod-stundenzettel table.noborder td:nth-child(6) {
|
||||
max-width: 100px;
|
||||
word-break: break-word;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Textarea in Edit-Mode kompakter (aber nicht in mobile-description-row) */
|
||||
.mod-stundenzettel tr.oddeven:not(.mobile-description-row) textarea {
|
||||
min-height: 50px;
|
||||
width: 150px !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
MOBILE FORMULARE - Separate Beschreibungszeile
|
||||
============================================ */
|
||||
/* Mobile-Zeilen anzeigen */
|
||||
.mod-stundenzettel .mobile-description-row {
|
||||
display: table-row;
|
||||
background: var(--colorbacklineimpair2, inherit) !important;
|
||||
}
|
||||
|
||||
.mod-stundenzettel .mobile-description-row td {
|
||||
padding: 8px !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
.mod-stundenzettel .mobile-description-row input,
|
||||
.mod-stundenzettel .mobile-description-row textarea {
|
||||
width: 100% !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Desktop-Spalten auf Mobile ausblenden */
|
||||
.mod-stundenzettel .mobile-hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
INLINE BESCHREIBUNG (unter Produktname)
|
||||
============================================ */
|
||||
.mod-stundenzettel .mobile-inline-desc {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 11px;
|
||||
line-height: 1.3;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,20 +286,3 @@
|
|||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
DARK MODE SUPPORT
|
||||
============================================ */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* Nur anwenden wenn Dolibarr Dark Theme aktiv (body hat dark-Klasse) */
|
||||
body.theme-eldy-dark .mod-stundenzettel .tabsAction,
|
||||
body[class*="dark"] .mod-stundenzettel .tabsAction {
|
||||
background: var(--colorbackbody, #1e1e1e);
|
||||
box-shadow: 0 -2px 8px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
body.theme-eldy-dark .mod-stundenzettel .mobile-description-row,
|
||||
body[class*="dark"] .mod-stundenzettel .mobile-description-row {
|
||||
background: var(--colorbacklineimpair2, #2d2d2d) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue