initial
This commit is contained in:
commit
89bffd2ee3
|
|
@ -0,0 +1,31 @@
|
|||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
*.pyd
|
||||
env/
|
||||
venv/
|
||||
.env
|
||||
|
||||
# SQLite DB
|
||||
*.db
|
||||
queue.db
|
||||
|
||||
# Flask debug / instance
|
||||
instance/
|
||||
|
||||
# Byte-compiled / cache
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# System
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Do not track Pipfile and Pipfile.lock
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
from flask import Flask, render_template, request, redirect, url_for, g, jsonify
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
DB = "queue.db"
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, "_db", None)
|
||||
if db is None:
|
||||
need_init = not os.path.exists(DB)
|
||||
db = g._db = sqlite3.connect(DB, check_same_thread=False)
|
||||
db.row_factory = sqlite3.Row
|
||||
if need_init:
|
||||
init_db(db)
|
||||
return db
|
||||
|
||||
def init_db(db):
|
||||
cur = db.cursor()
|
||||
cur.execute("""CREATE TABLE items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
number TEXT,
|
||||
status TEXT -- 'waiting', 'called', 'done'
|
||||
)""")
|
||||
db.commit()
|
||||
|
||||
@app.teardown_appcontext
|
||||
def close_db(exc):
|
||||
db = getattr(g, "_db", None)
|
||||
if db:
|
||||
db.close()
|
||||
|
||||
# Main display for clients
|
||||
@app.route("/")
|
||||
def index():
|
||||
db = get_db()
|
||||
cur = db.execute("SELECT number FROM items WHERE status='called' ORDER BY id DESC LIMIT 1")
|
||||
row = cur.fetchone()
|
||||
current = row["number"] if row else ""
|
||||
return render_template("index.html", current=current)
|
||||
|
||||
# API endpoint used by clients to poll current number (JSON)
|
||||
@app.route("/current")
|
||||
def current_api():
|
||||
db = get_db()
|
||||
cur = db.execute("SELECT number FROM items WHERE status='called' ORDER BY id DESC LIMIT 1")
|
||||
row = cur.fetchone()
|
||||
return jsonify(current=(row["number"] if row else ""))
|
||||
|
||||
# Admin UI: start/reset system by providing count of tickets (1..N)
|
||||
@app.route("/admin", methods=["GET", "POST"])
|
||||
def admin():
|
||||
db = get_db()
|
||||
if request.method == "POST":
|
||||
action = request.form.get("action")
|
||||
if action == "start":
|
||||
n = int(request.form.get("count", "0"))
|
||||
db.execute("DELETE FROM items")
|
||||
for i in range(1, n+1):
|
||||
db.execute("INSERT INTO items (number, status) VALUES (?, 'waiting')", (str(i),))
|
||||
db.commit()
|
||||
elif action == "call":
|
||||
num = request.form.get("num")
|
||||
# mark chosen number as called
|
||||
db.execute("UPDATE items SET status='called' WHERE number=? AND status='waiting'", (num,))
|
||||
db.commit()
|
||||
elif action == "done":
|
||||
num = request.form.get("num")
|
||||
db.execute("UPDATE items SET status='done' WHERE number=? AND status='called'", (num,))
|
||||
db.commit()
|
||||
elif action == "reset":
|
||||
db.execute("DELETE FROM items")
|
||||
db.commit()
|
||||
return redirect(url_for("admin"))
|
||||
|
||||
cur_wait = db.execute("SELECT number FROM items WHERE status='waiting' ORDER BY id").fetchall()
|
||||
cur_called = db.execute("SELECT number FROM items WHERE status='called' ORDER BY id").fetchall()
|
||||
cur_done = db.execute("SELECT number FROM items WHERE status='done' ORDER BY id").fetchall()
|
||||
return render_template("admin.html",
|
||||
waiting=[r["number"] for r in cur_wait],
|
||||
called=[r["number"] for r in cur_called],
|
||||
done=[r["number"] for r in cur_done])
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000, debug=True)
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Panel admina — kolejka</title>
|
||||
<style>body{font-family:Helvetica,Arial;margin:20px} .col{float:left;width:30%;padding:10px} .btn{display:inline-block;margin:3px;padding:6px 10px;background:#2b7;padding:color:#fff;border-radius:4px}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Panel admina</h2>
|
||||
|
||||
<form method="post">
|
||||
<label>Start — liczba numerów:
|
||||
<input name="count" type="number" min="1" value="20">
|
||||
</label>
|
||||
<button name="action" value="start">Start</button>
|
||||
<button name="action" value="reset">Reset</button>
|
||||
</form>
|
||||
|
||||
<div style="overflow:hidden;margin-top:20px">
|
||||
<div class="col">
|
||||
<h3>Oczekujące</h3>
|
||||
{% for n in waiting %}
|
||||
<form style="display:inline" method="post">
|
||||
<input type="hidden" name="num" value="{{n}}">
|
||||
<button name="action" value="call">{{n}}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p>brak</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Wywołane (obecne)</h3>
|
||||
{% for n in called %}
|
||||
<form style="display:block;margin-bottom:6px" method="post">
|
||||
<span style="font-size:20px;margin-right:8px">{{n}}</span>
|
||||
<input type="hidden" name="num" value="{{n}}">
|
||||
<button name="action" value="done">Przyszedł / Usuń</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p>brak</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h3>Obsłużone</h3>
|
||||
{% for n in done %}
|
||||
<div>{{n}}</div>
|
||||
{% else %}
|
||||
<p>brak</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Wywoływany numer</title>
|
||||
<style>body{font-family:Helvetica,Arial;margin:30px;text-align:center} .num{font-size:120px;font-weight:700}</style>
|
||||
<script>
|
||||
async function fetchCurrent(){
|
||||
try{
|
||||
const r = await fetch('/current');
|
||||
const j = await r.json();
|
||||
document.getElementById('num').textContent = j.current || '-';
|
||||
}catch(e){}
|
||||
}
|
||||
// poll co 2s
|
||||
setInterval(fetchCurrent, 2000);
|
||||
window.addEventListener('load', fetchCurrent);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Proszę podejść do okienka</h1>
|
||||
<div class="num" id="num">-</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue