Python

줄서기 시스템

스카이데이즈 2026. 2. 5. 08:52
728x90

 

✅ 구성

👤 사용자 화면

  • 이름 + 전화번호 입력
  • 내 번호 확인
  • 실시간 대기열 확인

🧑‍💼 관리자 화면

  • 다음 사람 호출 버튼
  • 현재 호출 번호 전체 화면 강조
  • 호출 시 소리 알림
  • 실시간 갱신

🔒 서버

  • Mutex (threading.Lock)
  • 동시 접속 안전
  • AJAX 기반 (새로고침 없음)

📁 파일 구조

queue_system/
 ├ app.py
 └ templates/
    ├ user.html
    └ admin.html

1️⃣ app.py (서버)

from flask import Flask, render_template, request, jsonify
import threading

app = Flask(__name__)

queue = []
queue_lock = threading.Lock()
next_id = 1
current_person = None

@app.route("/")
def user():
    return render_template("user.html")

@app.route("/admin")
def admin():
    return render_template("admin.html")

@app.route("/queue")
def get_queue():
    with queue_lock:
        return jsonify({
            "queue": queue,
            "current": current_person
        })

@app.route("/enqueue", methods=["POST"])
def enqueue():
    global next_id
    data = request.get_json(silent=True)

    if not data or "name" not in data or "phone" not in data:
        return jsonify({"error": "잘못된 요청"}), 400

    with queue_lock:
        person = {
            "id": next_id,
            "name": data["name"],
            "phone": data["phone"]
        }
        queue.append(person)
        next_id += 1

    return jsonify(person)
    

@app.route("/dequeue", methods=["POST"])
def dequeue():
    global current_person
    with queue_lock:
        current_person = queue.pop(0) if queue else None
    return jsonify(current_person)

if __name__ == "__main__":
    app.run(threaded=True, debug=True)

2️⃣ templates/user.html (사용자 화면)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>줄서기</title>
<style>
body { font-family: Arial; text-align: center; margin-top: 50px; }
input, button { padding: 10px; margin: 5px; }
#myNumber { font-size: 24px; color: green; }
</style>
</head>
<body>

<h1>🎟️ 줄서기</h1>

<input id="name" placeholder="이름">
<input id="phone" placeholder="전화번호">
<button onclick="join()">줄서기</button>

<div id="myNumber"></div>

<h2>대기열</h2>
<ul id="queue"></ul>

<script>
function refresh() {
    fetch('/queue').then(r=>r.json()).then(d=>{
        let ul = document.getElementById('queue');
        ul.innerHTML='';
        d.queue.forEach(p=>{
            let li=document.createElement('li');
            li.textContent=`${p.id}번 - ${p.name}`;
            ul.appendChild(li);
        });
    });
}


function join() {
    const nameInput = document.getElementById('name').value;
    const phoneInput = document.getElementById('phone').value;

    if (!nameInput || !phoneInput) {
        alert("이름과 전화번호를 입력하세요");
        return;
    }

    fetch('/enqueue', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            name: nameInput,
            phone: phoneInput
        })
    })
    .then(r => r.json())
    .then(p => {
        document.getElementById('myNumber').textContent =
            `✅ 접수 완료! 내 번호는 ${p.id}번입니다.`;
    });
}

setInterval(refresh,1000);
refresh();
</script>

</body>
</html>

3️⃣ templates/admin.html (관리자 + 대형 화면)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>관리자</title>
<style>
body {
    font-family: Arial;
    background: black;
    color: white;
    text-align: center;
}
#current {
    font-size: 120px;
    color: yellow;
    margin-top: 100px;
}
button {
    font-size: 30px;
    padding: 20px 40px;
}
</style>
</head>
<body>

<h1>📢 현재 호출 번호</h1>
<div id="current">-</div>
<button onclick="callNext()">다음 호출</button>

<audio id="beep">
    <source src="https://actions.google.com/sounds/v1/alarms/beep_short.ogg">
</audio>

<script>
function refresh() {
    fetch('/queue').then(r=>r.json()).then(d=>{
        if (d.current) {
            current.textContent = d.current.id + "번";
        }
    });
}

function callNext() {
    fetch('/dequeue',{method:'POST'})
        .then(r=>r.json())
        .then(p=>{
            if(p){
                current.textContent = p.id + "번";
                document.getElementById('beep').play();
            }
        });
}

setInterval(refresh,1000);
refresh();
</script>

</body>
</html>
 

 

🚀 실행 방법

pip install flask
python app.py
  • 사용자 화면 👉 http://서버주소:5000/
  • 관리자 👉 http://서버주소:5000/admin

 

- 관리자 페이지 접속시 비밀 번호 받기 및 전화번호 중복 처리 등 추가한 코드

lineup.zip
0.00MB

- 실행 파일 만들때 꼭 html도 포함되도록 만들어야 함

 pyinstaller.exe -F --add-data "templates:templates" app.py


 

728x90