- Endzeiten bei CheckOut und Startzeiten bei CheckIn komplett entfernt
- Zeiten einzeln Ein- und Ausblendbar gemacht - Quelle für Zeilenfarbe einstellbar gemacht - Zeiten werden jetzt bei erreichen bzw überschreiten immer markiert (nur die Zeit) - Nicht benötigte Spalten werden automatisch ausgeblendet - Config Datei Ausgedünnt (Bitte komplette Epirent-Settings (nicht Login) Sektion ersetzen
This commit is contained in:
461
Packmonitor.php
461
Packmonitor.php
@@ -1,7 +1,4 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
|
||||
|
||||
require('config.php');
|
||||
require('EpiApi.php');
|
||||
require('vendor/autoload.php');
|
||||
@@ -12,180 +9,330 @@ $Epi = new Epirent();
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
||||
<title>Packmonitor</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Packmonitor</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css">
|
||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<script type="text/javascript">
|
||||
// === Höhe der Scroll-Container bis Viewport-Ende anpassen ===
|
||||
function sizeScrollContainers() {
|
||||
$('.tableFixHead').each(function () {
|
||||
const rect = this.getBoundingClientRect();
|
||||
const bottomMargin = 16;
|
||||
const available = window.innerHeight - rect.top - bottomMargin;
|
||||
this.style.maxHeight = (available > 120 ? available : 120) + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
refreshCheckOutTable();
|
||||
refreshCheckInTable();
|
||||
});
|
||||
// === Scroll-/Interaktionsstatus je Scroller ===
|
||||
const scrollState = new WeakMap(); // { userActive:boolean, autoTimer:number|null, loopHeight:number }
|
||||
|
||||
function refreshCheckOutTable() {
|
||||
$('#getCheckOutTableHolder').load('sources/getCheckOutTable.php', function () {
|
||||
setTimeout(refreshCheckOutTable, 5000);
|
||||
});
|
||||
}
|
||||
function refreshCheckInTable() {
|
||||
$('#getCheckInTableHolder').load('sources/getCheckInTable.php', function () {
|
||||
setTimeout(refreshCheckInTable, 5000);
|
||||
});
|
||||
}
|
||||
function ensureState(el) {
|
||||
if (!scrollState.get(el)) scrollState.set(el, { userActive: false, autoTimer: null, loopHeight: 0 });
|
||||
return scrollState.get(el);
|
||||
}
|
||||
|
||||
function attachScrollGuards($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
if (!el || el.__guardsBound) return;
|
||||
const state = ensureState(el);
|
||||
|
||||
const markActive = () => {
|
||||
state.userActive = true;
|
||||
clearTimeout(state._quietT);
|
||||
state._quietT = setTimeout(() => { state.userActive = false; }, 800);
|
||||
stopAutoScroll($scroller);
|
||||
};
|
||||
|
||||
</script>
|
||||
$scroller.on('wheel touchstart touchmove keydown mousedown mouseenter', markActive);
|
||||
$scroller.on('mouseleave', () => setTimeout(() => maybeStartAutoScroll($scroller), 600));
|
||||
el.__guardsBound = true;
|
||||
}
|
||||
|
||||
</head>
|
||||
<body style="background-color: black;">
|
||||
// === Loop aufbauen: nahtloses Doppel nur bei Bedarf ===
|
||||
// Klont den ersten <tbody> als __loopClone ans Tabellenende, wenn Inhalt > Sichtbereich.
|
||||
function buildSeamlessLoop($table, $scroller) {
|
||||
$table.find('tbody.__loopClone').remove();
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg">
|
||||
<h2 class="text-light">Check-Out
|
||||
<?php
|
||||
if (CheckOut_FutureDays != -1) {
|
||||
echo "in den nächsten " . CheckOut_FutureDays . " Tagen";
|
||||
}
|
||||
?></h2>
|
||||
<table class="table table-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Kunde</th>
|
||||
<th scope="col">Event</th>
|
||||
<th scope="col">
|
||||
<?php
|
||||
if (!HideDispoTimes) {
|
||||
echo "Dispo-Start";
|
||||
}
|
||||
if (UsePackingNoteDateForCheckout) {
|
||||
echo "<br><i>Packen-Start</i></th>";
|
||||
} else {
|
||||
echo "<br><i>VB-Start</i></th>";
|
||||
}
|
||||
if (!HideCheckInTimeOnCheckout) {
|
||||
if(!HideDispoTimes){
|
||||
echo "<th scope='col'>Dispo-Ende<br><i>VB-Ende</i></th>";
|
||||
}else{
|
||||
echo "<th scope='col'><i>VB-Ende</i></th>";
|
||||
const $main = $table.find('tbody').first();
|
||||
const scEl = $scroller.get(0);
|
||||
const st = ensureState(scEl);
|
||||
|
||||
if ($main.length === 0 || $main.children().length === 0) {
|
||||
st.loopHeight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const mainH = $main.get(0).offsetHeight;
|
||||
const needScroll = mainH > scEl.clientHeight + 1;
|
||||
|
||||
if (!needScroll) {
|
||||
st.loopHeight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true');
|
||||
$table.append($clone);
|
||||
st.loopHeight = mainH; // Höhe des Original-Inhalts als Loop-Länge
|
||||
}
|
||||
|
||||
// === Auto-Scroll (nahtlos) ===
|
||||
function startAutoScroll($scroller, speedPx = 1, stepMs = 40) {
|
||||
const el = $scroller.get(0);
|
||||
const st = ensureState(el);
|
||||
|
||||
if (st.autoTimer) return; // schon aktiv
|
||||
if (st.loopHeight <= 0) return; // kein Overflow => nicht scrollen
|
||||
|
||||
const tick = () => {
|
||||
if (st.userActive) { stopAutoScroll($scroller); return; }
|
||||
el.scrollTop += speedPx;
|
||||
// Nahtlos: sobald wir das Ende des Original-Blocks überschreiten, ziehen wir loopHeight ab
|
||||
if (el.scrollTop >= st.loopHeight) {
|
||||
el.scrollTop -= st.loopHeight;
|
||||
}
|
||||
};
|
||||
|
||||
st.autoTimer = setInterval(tick, stepMs);
|
||||
}
|
||||
|
||||
function stopAutoScroll($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
const st = ensureState(el);
|
||||
if (st.autoTimer) {
|
||||
clearInterval(st.autoTimer);
|
||||
st.autoTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function maybeStartAutoScroll($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
const st = ensureState(el);
|
||||
if (st.userActive) return;
|
||||
if (st.loopHeight > 0) startAutoScroll($scroller, 1, 40);
|
||||
else stopAutoScroll($scroller);
|
||||
}
|
||||
|
||||
// === AJAX-Reload: relative Position innerhalb der Loop erhalten ===
|
||||
// Wir merken die Position modulo loopHeight; nach dem Reload setzen wir proportional um.
|
||||
function smartLoad($scroller, $table, $target, url, intervalMs) {
|
||||
const scEl = $scroller.get(0);
|
||||
const st = ensureState(scEl);
|
||||
|
||||
const oldLoop = st.loopHeight > 0 ? st.loopHeight : Math.max(1, scEl.scrollHeight - scEl.clientHeight);
|
||||
const posInLoop = st.loopHeight > 0 ? (scEl.scrollTop % oldLoop) : scEl.scrollTop;
|
||||
const posRatio = Math.min(1, posInLoop / oldLoop);
|
||||
|
||||
$target.load(url, function () {
|
||||
// Loop neu bewerten/aufbauen
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
|
||||
if (st.loopHeight > 0) {
|
||||
// Neue relative Position setzen (proportional)
|
||||
const newPos = Math.floor(posRatio * st.loopHeight);
|
||||
if (Math.abs(scEl.scrollTop - newPos) > 1) {
|
||||
// rAF für flüssiges Setzen außerhalb des load()-Layouts
|
||||
requestAnimationFrame(() => { scEl.scrollTop = newPos; });
|
||||
}
|
||||
// Auto-Scroll (wieder) starten
|
||||
stopAutoScroll($scroller);
|
||||
startAutoScroll($scroller, 1, 40);
|
||||
} else {
|
||||
// kein Overflow -> ganz oben und Auto-Scroll aus
|
||||
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||
stopAutoScroll($scroller);
|
||||
}
|
||||
|
||||
setTimeout(() => smartLoad($scroller, $table, $target, url, intervalMs), intervalMs);
|
||||
});
|
||||
}
|
||||
|
||||
// === Initialisierung ===
|
||||
$(document).ready(function () {
|
||||
sizeScrollContainers();
|
||||
$(window).on('resize', function () {
|
||||
sizeScrollContainers();
|
||||
// Nach Layoutwechsel neu entscheiden (nur 2 Tabellen)
|
||||
['#checkout', '#checkin'].forEach(prefix => {
|
||||
const $scroller = $(`${prefix}-scroll`);
|
||||
const $table = $(`${prefix}-table`);
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
maybeStartAutoScroll($scroller);
|
||||
});
|
||||
});
|
||||
|
||||
// Guards pro Scroller (nur 2)
|
||||
attachScrollGuards($('#checkout-scroll'));
|
||||
attachScrollGuards($('#checkin-scroll'));
|
||||
|
||||
// Erstladen je Tabelle: laden -> Loop bauen -> ggf. Auto-Scroll -> zyklisch refreshen
|
||||
function initOne(scrollerSel, tableSel, tbodySel, url, ms) {
|
||||
const $scroller = $(scrollerSel);
|
||||
const $table = $(tableSel);
|
||||
const $target = $(tbodySel);
|
||||
|
||||
$target.load(url, function () {
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
maybeStartAutoScroll($scroller);
|
||||
setTimeout(() => smartLoad($scroller, $table, $target, url, ms), ms);
|
||||
});
|
||||
}
|
||||
|
||||
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 5000);
|
||||
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 5000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Scroll-Wrapper je Tabelle */
|
||||
.tableFixHead {
|
||||
overflow-y: auto;
|
||||
/* Höhe wird per JS dynamisch gesetzt, damit genau bis zum Viewport-Ende gescrollt wird */
|
||||
max-height: 60vh; /* Fallback */
|
||||
border: 1px solid rgba(255,255,255,.1);
|
||||
border-radius: .25rem;
|
||||
}
|
||||
|
||||
/* Sticky Header */
|
||||
.tableFixHead thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2; /* über Body-Zellen */
|
||||
}
|
||||
|
||||
/* Saubere Hintergrundfarbe für sticky Header (Bootstrap .table-dark) */
|
||||
.table-dark thead th {
|
||||
background-color: #212529; /* gleiche Farbe wie .table-dark header */
|
||||
}
|
||||
|
||||
/* Optional: dünne Trennlinien */
|
||||
.table-dark tbody tr + tr td {
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
|
||||
body { background-color: black; margin-bottom: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Check-Out -->
|
||||
<div class="col-sm">
|
||||
<h2 class="text-light">Check-Out</h2>
|
||||
<div class="tableFixHead" id="checkout-scroll">
|
||||
<table class="table table-dark mb-0" id="checkout-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Kunde</th>
|
||||
<th scope="col">Event</th>
|
||||
<?php
|
||||
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){
|
||||
echo '<th scope="col">';
|
||||
}
|
||||
|
||||
if(ShowCheckoutTimeOnCheckout){
|
||||
echo "Dispo-Start";
|
||||
}
|
||||
if(ShowVorbereitungTimeOnCheckout){
|
||||
if(ShowCheckoutTimeOnCheckout){echo "<br>";}
|
||||
echo "VB-Start";
|
||||
}
|
||||
if(ShowPackagingTimeOnCheckout){
|
||||
if(ShowCheckoutTimeOnCheckout||ShowVorbereitungTimeOnCheckout){echo "<br>";}
|
||||
echo "Packen";
|
||||
}
|
||||
if(ShowDeliveryTimeOnCheckout){
|
||||
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout){echo "<br>";}
|
||||
echo "Liefern";
|
||||
}
|
||||
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
?>
|
||||
<th scope="col">Status</th>
|
||||
<?php
|
||||
if(ShowShippingIcons){
|
||||
echo "<th scope='col'>Shipping</th>";
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="getCheckOutTableHolder">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-lg">
|
||||
<h2 class="text-light">Check-In
|
||||
<?php
|
||||
if (CheckIn_FutureDays != -1) {
|
||||
echo "in den nächsten " . CheckIn_FutureDays . " Tagen";
|
||||
}
|
||||
?></h2>
|
||||
<table class="table table-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Kunde</th>
|
||||
<th scope="col">Event</th>
|
||||
|
||||
<?php
|
||||
if (!HideCheckOutTimeOnCheckin) {
|
||||
echo "<th scope='col'>Dispo-Start<br><i>RP-Start</i></th>";
|
||||
}
|
||||
|
||||
if(!HideDispoTimes){
|
||||
echo "<th scope='col'>Dispo-Ende";
|
||||
}else{
|
||||
echo "<th scope='col'>";
|
||||
}
|
||||
if (UsePackingNoteDateForCheckin) {
|
||||
echo "<br><i>Rücklieferung</i></th>";
|
||||
} else {
|
||||
echo "<br><i>RP-Ende</i></th>";
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<th scope="col">Status</th>
|
||||
<?php
|
||||
if(ShowShippingIcons){
|
||||
echo "<th scope='col'>Shipping</th>";
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="getCheckInTableHolder">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<th scope="col">Status</th>
|
||||
<?php
|
||||
if(ShowShippingIcons){
|
||||
echo "<th scope='col'>Shipping</th>";
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="getCheckOutTableHolder"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Check-In -->
|
||||
<div class="col-sm">
|
||||
<h2 class="text-light">Check-In</h2>
|
||||
<div class="tableFixHead" id="checkin-scroll">
|
||||
<table class="table table-dark mb-0" id="checkin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Kunde</th>
|
||||
<th scope="col">Event</th>
|
||||
<?php
|
||||
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin ||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){
|
||||
echo '<th scope="col">';
|
||||
}
|
||||
|
||||
if(ShowCheckInTimeOnCheckin){
|
||||
echo "Dispo-Ende";
|
||||
}
|
||||
if(ShowNachbereitungTimeOnCheckin){
|
||||
if(ShowCheckInTimeOnCheckin){echo "<br>";}
|
||||
echo "Nachbereitung";
|
||||
}
|
||||
if(ShowRePackagingTimeOnCheckin){
|
||||
if(ShowCheckInTimeOnCheckin||ShowNachbereitungTimeOnCheckin){echo "<br>";}
|
||||
echo "Zurückpacken";
|
||||
}
|
||||
if(ShowReDeliveryTimeOnCheckin){
|
||||
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin){echo "<br>";}
|
||||
echo "Rückliefern";
|
||||
}
|
||||
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){
|
||||
echo '</th>';
|
||||
}
|
||||
|
||||
?>
|
||||
<th scope="col">Status</th>
|
||||
<?php
|
||||
if(ShowShippingIcons){
|
||||
echo "<th scope='col'>Shipping</th>";
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="getCheckInTableHolder"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
|
||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
function getTimeFromSeconds(string $timestring) {
|
||||
|
||||
$hours = floor($timestring / 3600);
|
||||
$mins = floor($timestring / 60 % 60);
|
||||
$secs = floor($timestring % 60);
|
||||
|
||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
||||
|
||||
return $timeFormat;
|
||||
$hours = floor($timestring / 3600);
|
||||
$mins = floor($timestring / 60 % 60);
|
||||
return sprintf('%02d:%02d', $hours, $mins);
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user