用deepseek写了一个简单的叫号系统
2025-02-12 08:42 阅读(66)

要实现一个基于 ThinkPHP 6.1 的排队叫号系统,我们可以按照以下步骤进行开发。系统将使用 Redis 作为队列存储,WebSocket 实现实时推送,并提供 API 接口供用户和管理员操作。

1. 环境准备

首先,确保你已经安装了以下组件:


PHP 7.4+

ThinkPHP 6.1

Redis

MySQL(可选,用于持久化历史记录)

WebSocket 服务器(如 Swoole 或 Workerman)


2. 安装依赖

在 ThinkPHP 6.1 项目中,安装 Redis 和 WebSocket 相关的扩展包。

composer require topthink/think-redis
composer require workerman/workerman

3. 配置 Redis

在 config/cache.php 中配置 Redis 连接:

return [
    'default' => 'redis',
    'stores'  => [
        'redis' => [
            'type'       => 'redis',
            'host'       => '127.0.0.1',
            'port'       => 6379,
            'password'   => '',
            'select'    => 0,
            'timeout'    => 0,
            'persistent' => false,
        ],
    ],
];

4. 创建队列管理类

创建一个队列管理类 app\service\QueueService.php,用于管理 Redis 队列。

namespace app\service;

use think\facade\Cache;

class QueueService
{
    protected $queueKey = 'queue:numbers';
    protected $webSocketService;

    public function __construct()
    {
        $this->webSocketService = new WebSocketService();
    }

    // 取号
    public function getNumber()
    {
        $number = Cache::incr('queue:counter');
        Cache::rPush($this->queueKey, $number);
        return $number;
    }

    // 叫号
    public function callNumber()
    {
        $number = Cache::lPop($this->queueKey);
        if ($number) {
            // 推送叫号信息到 WebSocket
            $this->webSocketService->pushToAll(['type' => 'call', 'number' => $number]);
        }
        return $number;
    }

    // 获取当前排队状态
    public function getQueueStatus()
    {
        return Cache::lRange($this->queueKey, 0, -1);
    }
}

5. 创建 WebSocket 服务类

在 app\service 目录下创建一个 WebSocketService.php 文件,用于封装 WebSocket 服务器的逻辑。

namespace app\service;

use Workerman\Worker;
use Workerman\Connection\TcpConnection;

class WebSocketService
{
    protected $worker;

    public function __construct($address = 'websocket://0.0.0.0:2346')
    {
        $this->worker = new Worker($address);

        $this->worker->onConnect = function(TcpConnection $connection) {
            echo "New connection\n";
        };

        $this->worker->onMessage = function(TcpConnection $connection, $data) {
            // 处理客户端发送的消息
            $connection->send(json_encode(['type' => 'message', 'content' => 'Hello']));
        };

        $this->worker->onClose = function(TcpConnection $connection) {
            echo "Connection closed\n";
        };
    }

    // 启动 WebSocket 服务器
    public function start()
    {
        Worker::runAll();
    }

    // 推送消息到所有客户端
    public function pushToAll($message)
    {
        foreach ($this->worker->connections as $connection) {
            $connection->send(json_encode($message));
        }
    }
}

6. 创建 API 接口

在 app\controller\QueueController.php 中创建 API 接口。

namespace app\controller;

use app\service\QueueService;
use think\facade\Request;

class QueueController
{
    protected $queueService;

    public function __construct()
    {
        $this->queueService = new QueueService();
    }

    // 取号
    public function getNumber()
    {
        $number = $this->queueService->getNumber();
        return json(['code' => 200, 'message' => '取号成功', 'number' => $number]);
    }

    // 叫号
    public function callNumber()
    {
        $number = $this->queueService->callNumber();
        return json(['code' => 200, 'message' => '叫号成功', 'number' => $number]);
    }

    // 查看当前排队状态
    public function getQueueStatus()
    {
        $status = $this->queueService->getQueueStatus();
        return json(['code' => 200, 'message' => '获取成功', 'status' => $status]);
    }
}

7. 路由配置

在 route/route.php 中配置路由。

use think\facade\Route;

Route::get('queue/getNumber', 'QueueController/getNumber');
Route::get('queue/callNumber', 'QueueController/callNumber');
Route::get('queue/getQueueStatus', 'QueueController/getQueueStatus');

8. 前端实现

在前端页面中,使用 WebSocket 连接服务器,并实时接收叫号信息。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>排队叫号系统</title>
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Font Awesome -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
    <style>
        body {
            background-color: #f8f9fa;
            padding: 20px;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
        }
        .card {
            margin-top: 20px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        .card-header {
            background-color: #007bff;
            color: white;
            font-size: 1.5rem;
            font-weight: bold;
        }
        .btn-primary {
            background-color: #007bff;
            border-color: #007bff;
        }
        .btn-primary:hover {
            background-color: #0056b3;
            border-color: #0056b3;
        }
        .btn-success {
            background-color: #28a745;
            border-color: #28a745;
        }
        .btn-success:hover {
            background-color: #218838;
            border-color: #218838;
        }
        .status-box {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            margin-top: 20px;
        }
        .status-box h3 {
            margin-bottom: 15px;
            font-size: 1.25rem;
            color: #333;
        }
        .status-box ul {
            list-style-type: none;
            padding: 0;
        }
        .status-box ul li {
            padding: 10px;
            border-bottom: 1px solid #eee;
            font-size: 1rem;
            color: #555;
        }
        .status-box ul li:last-child {
            border-bottom: none;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <div class="card-header text-center">
            排队叫号系统
        </div>
        <div class="card-body">
            <div class="d-grid gap-2">
                <button class="btn btn-primary btn-lg" onclick="getNumber()">
                    <i class="fas fa-ticket-alt"></i> 取号
                </button>
                <button class="btn btn-success btn-lg" onclick="callNumber()">
                    <i class="fas fa-bullhorn"></i> 叫号
                </button>
            </div>
            <div class="status-box">
                <h3>当前排队状态</h3>
                <ul id="status"></ul>
            </div>
        </div>
    </div>
</div>

<script>
    const ws = new WebSocket('ws://127.0.0.1:2346');

    ws.onmessage = function(event) {
        const data = JSON.parse(event.data);
        if (data.type === 'call') {
            alert(`叫号:${data.number}`);
        }
    };

    function getNumber() {
        fetch('api/queue/getNumber')
            .then(response => response.json())
            .then(data => {
                alert(`取号成功:${data.number}`);
            });
    }

    function callNumber() {
        fetch('api/queue/callNumber')
            .then(response => response.json())
            .then(data => {
                alert(`叫号成功:${data.number}`);
            });
    }

    function getQueueStatus() {
        fetch('api/queue/getQueueStatus')
            .then(response => response.json())
            .then(data => {
                const statusList = document.getElementById('status');
                statusList.innerHTML = data.status.map(number => `<li>号码:${number}</li>`).join('');
            });
    }

    // 定时获取排队状态
    setInterval(getQueueStatus, 5000);
</script>

<!-- Bootstrap JS and dependencies -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>
</body>
</html>

9. 运行 WebSocket 服务器

在命令行中运行 WebSocket 服务器:

php websocket.php start

10. 运行 ThinkPHP 项目

启动 ThinkPHP 项目: php websocket.php start


https://www.zuocode.com