Implementieren der PWA, Multi-Instanzen-Passwort-Schutz und Kassen-Löschfunktion

This commit is contained in:
2026-02-24 16:33:16 +01:00
parent 1a12dcd1d0
commit 8b12d17935
11 changed files with 645 additions and 153 deletions

View File

@@ -1,125 +1,176 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-Type" content="text/html; utf-8" />
<meta http-equiv="Pragma" content="cache" />
<meta name="robots" content="INDEX,FOLLOW" />
<meta http-equiv="content-Language" content="de" />
<meta name="description" content="Viele Obststände in Deutschland haben keine elektronische Kasse. Aufgrund der geringen Zahl unterschiedlicher Artikel bietet sich diese simple Rechner-App an, die bis zu sechs verschiedene Artikel in unterschiedlicher Stückzahl summieren kann." />
<meta name="keywords" content="rechner kasse calculator bargeld artikel obst erdbeeren spargel kirschen verkaufsstand wechselgeld kostenlos opensource werbefrei" />
<meta name="author" content="Markus Busche" />
<meta name="publisher" content="Markus Busche" />
<meta name="copyright" content="2024 Markus Busche" />
<meta name="audience" content="Alle" />
<meta name="page-type" content="HTML-Formular" />
<meta name="page-topic" content="Dienstleistung" />
<meta http-equiv="Reply-to" content="m.busche@mailbox.org" />
<meta name="expires" content="" />
<meta name="revisit-after" content="2 days" />
<meta name="robots" content="noindex,nofollow" />
<title>erdbeerhannah 🍓💶</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#dc3545">
<link rel="apple-touch-icon" href="/static/icon-192x192.png">
<style>
body, html {
body,
html {
height: 100%;
}
.table-container {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.table {
width: 100%;
height: 100%;
table-layout: fixed;
}
.table td {
height: calc(100vh / 6); /* Höhe der Zeilen dynamisch anpassen */
height: calc(100vh / 6);
vertical-align: middle;
text-align: center;
}
.btn {
width: 100%; /* Button füllt die Zelle */
height: 100%; /* Button füllt die Zelle */
width: 100%;
height: 100%;
white-space: normal;
}
.bold-row {
font-weight: bold;
font-size: 250%;
}
.large-font {
font-size: 300%;
}
.custom-btn-size {
font-size: 180%;
font-size: 180%;
}
.custom-btn-size-med {
font-size: 150%;
font-size: 150%;
}
.input-container {
display: flex;
flex-direction: column; /* Ändert die Richtung der Flex-Elemente zu Spalten */
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.input-container input {
margin-bottom: 10px;
width: 80%; /* Setzt die Breite des Eingabefelds */
width: 80%;
text-align: center;
font-size: 1.5rem;
}
.input-container button {
width: 80%; /* Setzt die Breite des Buttons */
width: 80%;
}
</style>
</head>
<script>
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
</script>
<body>
<div class="container-fluid table-container">
<table class="table table-bordered">
<form method="post">
<tbody>
<tr class="bold-row">
<td colspan="3">erdbeerrechner 🍓💶</td>
<td colspan="2">erdbeerrechner 🍓💶</td>
<td><a href="{{ url_for('admin', instance_id=instance_id) }}"
class="btn btn-outline-secondary custom-btn-size-med">⚙️ Setup</a></td>
</tr>
<tr>
<td><button type="submit" name="wert" value="4.9" data-toggle="tooltip" data-placement="top" title="500g Erdbeeren" class="btn btn-xl btn-primary custom-btn-size">🍓 4,90€ ({{ item1 }})</button></td>
<td><button type="submit" name="wert" value="4.8" data-toggle="tooltip" data-placement="top" title="Marmelade groß" class="btn btn-xl btn-danger custom-btn-size">🫙🫙 4,80€ ({{ item2 }})</button></td>
<td><button type="submit" name="wert" value="3.3" data-toggle="tooltip" data-placement="top" title="Marmelade klein" class="btn btn-xl btn-danger custom-btn-size">🫙 3,30€ ({{ item3 }})</button></td>
{% for i in range(1, 4) %}
{% set prod = products[i] %}
<td>
<button type="submit" name="position" value="{{ i }}" title="{{ prod['name'] }}"
class="btn btn-xl {{ prod['color_class'] }} custom-btn-size">
{{ prod['icon'] }} <br> {{ '{:,.2f}'.format(prod['price']).replace('.', ',') }}€ <br>
({{ items[i] }})
</button>
</td>
{% endfor %}
</tr>
<tr>
<td><button type="submit" name="wert" value="5.0" data-toggle="tooltip" data-placement="top" title="500g Kirschen" class="btn btn-xl btn-warning custom-btn-size">🍒 5,00€ ({{ item4 }})</button></td>
<td><button type="submit" name="wert" value="4.5" data-toggle="tooltip" data-placement="top" title="500g Himbeeren" class="btn btn-xl btn-warning custom-btn-size">🫐 4,50€ ({{ item5 }})</button></td>
<td><button type="submit" name="wert" value="0.2" data-toggle="tooltip" data-placement="top" title="Tragetasche" class="btn btn-xl btn-success custom-btn-size">🛍️ 0,20€ ({{ item6 }})</button></td>
{% for i in range(4, 7) %}
{% set prod = products[i] %}
<td>
<button type="submit" name="position" value="{{ i }}" title="{{ prod['name'] }}"
class="btn btn-xl {{ prod['color_class'] }} custom-btn-size">
{{ prod['icon'] }} <br> {{ '{:,.2f}'.format(prod['price']).replace('.', ',') }}€ <br>
({{ items[i] }})
</button>
</td>
{% endfor %}
</tr>
<tr>
<td data-toggle="tooltip" data-placement="top" title="Summe" class="bold-row">🫰 {{ gesamtwert }}€</td>
<td title="Summe" class="bold-row">🫰 {{ gesamtwert.replace('.', ',') }}€</td>
<td>
<div class="input-container">
<input type="text" class="form-control" name="given" placeholder="{{ given }}">
<button type="submit" name="wert" value="-2" data-toggle="tooltip" data-placement="top" title="Wechselgeld berechnen" class="btn btn-xl btn-primary custom-btn-size-med">🧾</button>
<input type="number" step="0.01" class="form-control" name="given"
placeholder="{{ given }}" value="{% if given != '0' %}{{ given }}{% endif %}">
<button type="submit" name="action" value="calculate_change"
title="Wechselgeld berechnen" class="btn btn-xl btn-primary custom-btn-size-med">🧾
Berechnen</button>
</div>
</td>
<td data-toggle="tooltip" data-placement="top" title="Wechselgeld" class="bold-row {{ background }}">🪙 {{ change }}€</td>
<td title="Wechselgeld" class="bold-row {{ background }}">🪙 {{ change.replace('.', ',') }}€
</td>
</tr>
<tr>
<td colspan="3"><button type="submit" name="wert" value="0" id="reset" class="btn btn-xl btn-dark custom-btn-size">Reset 🦭</button></td>
<td colspan="3">
<button type="submit" name="action" value="reset" id="reset"
class="btn btn-xl btn-dark custom-btn-size">Reset 🦭</button>
</td>
</tr>
<tr>
<td colspan="3">Made with ♥️, marmalade and zero knowledge in <a href="https://kiel-sailing-city.de/" target="_blank">Kiel Strawberry City.</a><br>
Version: {{ version }} ({{ g.request_time() }}), <a href="https://gitea.elpatron.me/elpatron/erdbeerhannah/src/branch/main/README.md" target="_blank">Infos</a></td>
<td colspan="3">Made with ♥️, marmalade and zero knowledge in <a
href="https://kiel-sailing-city.de/" target="_blank">Kiel Strawberry City.</a><br>
Version: {{ version }}, Instanz: {{ instance_id[:8] }}...
<button type="button" onclick="shareInstance()"
class="btn btn-sm btn-outline-primary ml-2">📤 URL Teilen</button>
</td>
</tr>
</tbody>
</tbody>
</form>
</table>
</div>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
// Save instance to localStorage for the landing page
const instanceId = "{{ instance_id }}";
let saved = JSON.parse(localStorage.getItem('erdbeerkassen')) || [];
// Optional: remove if exists so it gets pushed to the end (most recent)
saved = saved.filter(i => i.id !== instanceId);
saved.push({ id: instanceId, date: new Date().toISOString() });
localStorage.setItem('erdbeerkassen', JSON.stringify(saved));
function shareInstance() {
const url = window.location.href;
if (navigator.share) {
navigator.share({
title: 'erdbeerrechner 🍓💶',
url: url
}).catch(console.error);
} else {
navigator.clipboard.writeText(url);
alert('URL in die Zwischenablage kopiert!');
}
}
</script>
</body>
</html>
</html>