首页 / 应用软件 / 实战教学,为网站集成在线预约排队与叫号系统

实战教学,为网站集成在线预约排队与叫号系统

实战教学:为网站集成在线预约排队与叫号系统——通过WordPress代码二次开发实现常用互联网小工具功能

引言:数字化时代下的服务升级需求

在当今快节奏的数字化社会中,无论是医疗机构、教育机构、政府服务大厅,还是餐饮、美容、维修等商业服务场所,排队等待已成为客户体验中最令人不满的环节之一。传统的排队方式不仅消耗客户宝贵时间,也增加了服务场所的管理难度和人力成本。随着互联网技术的普及,在线预约排队与叫号系统应运而生,成为提升服务效率、优化客户体验的重要工具。

对于大多数中小型企业和机构而言,定制开发一套完整的预约排队系统成本高昂,维护复杂。而WordPress作为全球最流行的内容管理系统,以其强大的扩展性和灵活性,为我们提供了一个经济高效的解决方案。本文将深入探讨如何通过WordPress程序的代码二次开发,为网站集成一套功能完善的在线预约排队与叫号系统,实现这一常用互联网小工具功能。

第一章:系统需求分析与设计规划

1.1 业务场景分析

在开始技术实现之前,我们首先需要明确系统的使用场景和功能需求。一个典型的在线预约排队与叫号系统应包含以下核心功能:

  1. 客户端功能

    • 服务项目浏览与选择
    • 预约时间选择与提交
    • 排队号码获取与状态查询
    • 实时排队位置提醒
    • 预约取消与改期
  2. 管理端功能

    • 预约申请审核与管理
    • 排队队列实时监控
    • 叫号操作与控制
    • 服务窗口/人员管理
    • 数据统计与分析报表
  3. 现场显示功能

    • 当前叫号信息展示
    • 等待队列信息展示
    • 服务窗口状态显示

1.2 技术架构设计

基于WordPress的二次开发,我们采用以下技术架构:

  • 前端展示层:使用WordPress主题模板系统,结合HTML5、CSS3和JavaScript(特别是AJAX技术)实现用户界面
  • 业务逻辑层:通过自定义Post Type、Taxonomy和Meta Box构建数据模型,利用Action和Filter钩子扩展核心功能
  • 数据持久层:利用WordPress数据库结构,创建自定义数据表存储预约和排队信息
  • 实时通信层:采用WebSocket或轮询技术实现排队状态的实时更新
  • 外部接口层:集成短信/邮件通知API,提供状态提醒服务

第二章:WordPress开发环境搭建与基础配置

2.1 开发环境准备

在开始开发之前,我们需要搭建一个适合WordPress二次开发的环境:

  1. 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
  2. WordPress安装:下载最新版WordPress,完成基础安装
  3. 开发工具配置

    • 代码编辑器:VS Code或PHPStorm
    • 版本控制:Git初始化仓库
    • 调试工具:安装Query Monitor、Debug Bar等调试插件
    • 代码标准:配置PHP_CodeSniffer遵循WordPress编码标准

2.2 创建自定义插件

为了避免主题更新导致功能丢失,我们将所有功能集成到一个独立插件中:

<?php
/**
 * Plugin Name: 智能预约排队系统
 * Plugin URI: https://yourwebsite.com/
 * Description: 为WordPress网站集成在线预约排队与叫号功能
 * Version: 1.0.0
 * Author: 您的名称
 * License: GPL v2 or later
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('APPOINTMENT_SYSTEM_VERSION', '1.0.0');
define('APPOINTMENT_SYSTEM_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('APPOINTMENT_SYSTEM_PLUGIN_URL', plugin_dir_url(__FILE__));

// 初始化插件
require_once APPOINTMENT_SYSTEM_PLUGIN_DIR . 'includes/class-appointment-system.php';

function run_appointment_system() {
    $plugin = new Appointment_System();
    $plugin->run();
}
run_appointment_system();

第三章:数据模型设计与数据库结构

3.1 自定义Post Type设计

我们将使用WordPress的自定义文章类型来管理预约和服务项目:

// 注册服务项目自定义文章类型
function register_service_post_type() {
    $labels = array(
        'name'               => '服务项目',
        'singular_name'      => '服务项目',
        'menu_name'          => '服务项目管理',
        'add_new'            => '添加服务项目',
        'add_new_item'       => '添加新服务项目',
        'edit_item'          => '编辑服务项目',
        'new_item'           => '新服务项目',
        'view_item'          => '查看服务项目',
        'search_items'       => '搜索服务项目',
        'not_found'          => '未找到服务项目',
        'not_found_in_trash' => '回收站中无服务项目'
    );
    
    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array('slug' => 'service'),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => 5,
        'menu_icon'          => 'dashicons-calendar-alt',
        'supports'           => array('title', 'editor', 'thumbnail', 'excerpt'),
        'show_in_rest'       => true
    );
    
    register_post_type('service', $args);
}
add_action('init', 'register_service_post_type');

3.2 自定义数据库表设计

对于排队和预约数据,我们需要创建独立的数据库表以保证查询效率:

// 创建自定义数据库表
function create_appointment_tables() {
    global $wpdb;
    
    $charset_collate = $wpdb->get_charset_collate();
    $table_name_appointments = $wpdb->prefix . 'appointments';
    $table_name_queues = $wpdb->prefix . 'queues';
    
    // 预约表
    $sql_appointments = "CREATE TABLE IF NOT EXISTS $table_name_appointments (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        user_id bigint(20) DEFAULT 0,
        service_id bigint(20) NOT NULL,
        appointment_date date NOT NULL,
        time_slot varchar(50) NOT NULL,
        customer_name varchar(100) NOT NULL,
        customer_phone varchar(20) NOT NULL,
        customer_email varchar(100),
        status varchar(20) DEFAULT 'pending',
        queue_number varchar(50),
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY service_id (service_id),
        KEY appointment_date (appointment_date),
        KEY status (status)
    ) $charset_collate;";
    
    // 排队表
    $sql_queues = "CREATE TABLE IF NOT EXISTS $table_name_queues (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        appointment_id bigint(20) NOT NULL,
        service_point_id bigint(20) NOT NULL,
        queue_number varchar(50) NOT NULL,
        position int(11) NOT NULL,
        estimated_wait_time int(11) DEFAULT 0,
        called_at datetime,
        served_at datetime,
        status varchar(20) DEFAULT 'waiting',
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY appointment_id (appointment_id),
        KEY service_point_id (service_point_id),
        KEY status (status)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql_appointments);
    dbDelta($sql_queues);
}
register_activation_hook(__FILE__, 'create_appointment_tables');

第四章:前端预约界面开发

4.1 预约表单设计与实现

创建一个用户友好的预约表单是系统的关键:

// 预约表单短代码
function appointment_form_shortcode($atts) {
    ob_start();
    
    // 获取服务项目
    $services = get_posts(array(
        'post_type' => 'service',
        'posts_per_page' => -1,
        'orderby' => 'title',
        'order' => 'ASC'
    ));
    
    // 获取可预约日期(未来30天)
    $available_dates = array();
    $today = new DateTime();
    for ($i = 1; $i <= 30; $i++) {
        $date = clone $today;
        $date->add(new DateInterval("P{$i}D"));
        // 排除周末
        if ($date->format('N') < 6) {
            $available_dates[] = $date->format('Y-m-d');
        }
    }
    
    // 定义时间槽
    $time_slots = array(
        '09:00-10:00',
        '10:00-11:00',
        '11:00-12:00',
        '13:00-14:00',
        '14:00-15:00',
        '15:00-16:00',
        '16:00-17:00'
    );
    ?>
    
    <div class="appointment-form-container">
        <h2>在线预约</h2>
        <form id="appointment-form" method="post">
            <?php wp_nonce_field('submit_appointment', 'appointment_nonce'); ?>
            
            <div class="form-group">
                <label for="service_id">选择服务项目 *</label>
                <select id="service_id" name="service_id" required>
                    <option value="">请选择服务项目</option>
                    <?php foreach ($services as $service): ?>
                    <option value="<?php echo $service->ID; ?>">
                        <?php echo esc_html($service->post_title); ?>
                    </option>
                    <?php endforeach; ?>
                </select>
            </div>
            
            <div class="form-group">
                <label for="appointment_date">选择预约日期 *</label>
                <select id="appointment_date" name="appointment_date" required>
                    <option value="">请选择日期</option>
                    <?php foreach ($available_dates as $date): ?>
                    <option value="<?php echo $date; ?>">
                        <?php echo date('Y年m月d日', strtotime($date)); ?>
                    </option>
                    <?php endforeach; ?>
                </select>
            </div>
            
            <div class="form-group">
                <label for="time_slot">选择时间段 *</label>
                <select id="time_slot" name="time_slot" required>
                    <option value="">请选择时间段</option>
                    <?php foreach ($time_slots as $slot): ?>
                    <option value="<?php echo $slot; ?>"><?php echo $slot; ?></option>
                    <?php endforeach; ?>
                </select>
            </div>
            
            <div class="form-group">
                <label for="customer_name">姓名 *</label>
                <input type="text" id="customer_name" name="customer_name" required>
            </div>
            
            <div class="form-group">
                <label for="customer_phone">手机号 *</label>
                <input type="tel" id="customer_phone" name="customer_phone" required>
            </div>
            
            <div class="form-group">
                <label for="customer_email">电子邮箱</label>
                <input type="email" id="customer_email" name="customer_email">
            </div>
            
            <div class="form-group">
                <button type="submit" id="submit-appointment">提交预约</button>
            </div>
            
            <div id="appointment-response"></div>
        </form>
    </div>
    
    <script>
    jQuery(document).ready(function($) {
        $('#appointment-form').on('submit', function(e) {
            e.preventDefault();
            
            var formData = $(this).serialize();
            
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action: 'submit_appointment',
                    data: formData
                },
                beforeSend: function() {
                    $('#submit-appointment').prop('disabled', true).text('提交中...');
                },
                success: function(response) {
                    if (response.success) {
                        $('#appointment-response').html(
                            '<div class="success-message">' + 
                            '预约成功!您的排队号码是:<strong>' + response.data.queue_number + '</strong>' +
                            '</div>'
                        );
                        $('#appointment-form')[0].reset();
                    } else {
                        $('#appointment-response').html(
                            '<div class="error-message">' + response.data + '</div>'
                        );
                    }
                    $('#submit-appointment').prop('disabled', false).text('提交预约');
                }
            });
        });
    });
    </script>
    
    <?php
    return ob_get_clean();
}
add_shortcode('appointment_form', 'appointment_form_shortcode');

4.2 实时排队状态展示

// 排队状态展示短代码
function queue_status_shortcode() {
    ob_start();
    ?>
    
    <div class="queue-status-container">
        <h2>实时排队状态</h2>
        
        <div class="current-calls">
            <h3>当前叫号</h3>
            <div id="current-calls-display">
                <!-- 通过AJAX动态加载 -->
            </div>
        </div>
        
        <div class="waiting-queue">
            <h3>等待队列</h3>
            <div id="waiting-queue-display">
                <!-- 通过AJAX动态加载 -->
            </div>
        </div>
        
        <div class="queue-search">
            <h3>查询我的排队状态</h3>
            <input type="text" id="queue-number-input" placeholder="请输入您的排队号码">
            <button id="check-queue-status">查询</button>
            <div id="personal-queue-status"></div>
        </div>
    </div>
    
    <script>
    jQuery(document).ready(function($) {
        // 更新排队状态
        function updateQueueStatus() {
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'GET',
                data: {
                    action: 'get_queue_status'
                },
                success: function(response) {
                    if (response.success) {
                        $('#current-calls-display').html(response.data.current_calls);
                        $('#waiting-queue-display').html(response.data.waiting_queue);
                    }
                }
            });
        }
        
        // 初始加载
        updateQueueStatus();
        
        // 每30秒更新一次
        setInterval(updateQueueStatus, 30000);
        
        // 查询个人排队状态
        $('#check-queue-status').on('click', function() {
            var queueNumber = $('#queue-number-input').val();
            
            if (!queueNumber) {
                alert('请输入排队号码');
                return;
            }
            
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action: 'get_personal_queue_status',
                    queue_number: queueNumber
                },
                success: function(response) {
                    if (response.success) {
                        $('#personal-queue-status').html(response.data);
                    } else {
                        $('#personal-queue-status').html(
                            '<div class="error">' + response.data + '</div>'
                        );
                    }
                }
            });
        });
    });
    </script>
    
    <?php
    return ob_get_clean();
}
add_shortcode('queue_status', 'queue_status_shortcode');

第五章:后台管理系统开发

5.1 预约管理界面

// 添加预约管理菜单
function add_appointment_admin_menu() {
    add_menu_page(
        '预约管理',
        '预约管理',
        'manage_options',
        'appointment-management',
        'display_appointment_management_page',
        'dashicons-calendar',
        6
    );
    
    add_submenu_page(
        'appointment-management',
        '排队叫号',
        '排队叫号',
        'manage_options',
        'queue-management',
        'display_queue_management_page'
    );
    
    add_submenu_page(
        'appointment-management',
        '服务窗口设置',
        '服务窗口设置',
        'manage_options',
        'service-points',
        'display_service_points_page'
    );
}
add_action('admin_menu', 'add_appointment_admin_menu');

// 预约管理页面
function display_appointment_management_page() {
    global $wpdb;
    
    $table_name = $wpdb->prefix . 'appointments';
    
    // 处理批量操作
    if (isset($_POST['bulk_action']) && isset($_POST['appointment_ids'])) {
        $action = $_POST['bulk_action'];
        $ids = implode(',', array_map('intval', $_POST['appointment_ids']));
        
        switch ($action) {
            case 'confirm':
                $wpdb->query("UPDATE $table_name SET status = 'confirmed' WHERE id IN ($ids)");
                break;
            case 'cancel':
                $wpdb->query("UPDATE $table_name SET status = 'cancelled' WHERE id IN ($ids)");
                break;
            case 'delete':
                $wpdb->query("DELETE FROM $table_name WHERE id IN ($ids)");
                break;
        }
    }
    
    // 获取预约数据
    $per_page = 20;
    $current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
    $offset = ($current_page - 1) * $per_page;
    
    $where_conditions = array('1=1');
    $where_values = array();
    
    // 筛选条件
    if (!empty($_GET['status'])) {
        $where_conditions[] = 'status = %s';

5.2 排队叫号管理界面

// 排队叫号管理页面
function display_queue_management_page() {
    global $wpdb;
    
    $appointments_table = $wpdb->prefix . 'appointments';
    $queues_table = $wpdb->prefix . 'queues';
    $service_points_table = $wpdb->prefix . 'service_points';
    
    // 获取所有服务窗口
    $service_points = $wpdb->get_results("SELECT * FROM $service_points_table WHERE is_active = 1");
    
    // 处理叫号操作
    if (isset($_POST['call_next']) && isset($_POST['service_point_id'])) {
        $service_point_id = intval($_POST['service_point_id']);
        
        // 获取当前窗口的下一个排队号
        $next_queue = $wpdb->get_row($wpdb->prepare(
            "SELECT q.*, a.customer_name, a.service_id 
             FROM $queues_table q 
             LEFT JOIN $appointments_table a ON q.appointment_id = a.id 
             WHERE q.service_point_id = %d 
             AND q.status = 'waiting' 
             ORDER BY q.position ASC 
             LIMIT 1",
            $service_point_id
        ));
        
        if ($next_queue) {
            // 更新为已叫号状态
            $wpdb->update(
                $queues_table,
                array(
                    'status' => 'called',
                    'called_at' => current_time('mysql')
                ),
                array('id' => $next_queue->id)
            );
            
            echo '<div class="notice notice-success"><p>已叫号:' . esc_html($next_queue->queue_number) . '</p></div>';
            
            // 记录叫号历史
            $wpdb->insert(
                $wpdb->prefix . 'call_history',
                array(
                    'queue_id' => $next_queue->id,
                    'service_point_id' => $service_point_id,
                    'called_at' => current_time('mysql'),
                    'operator_id' => get_current_user_id()
                )
            );
        }
    }
    
    // 处理完成服务操作
    if (isset($_POST['complete_service']) && isset($_POST['queue_id'])) {
        $queue_id = intval($_POST['queue_id']);
        
        $wpdb->update(
            $queues_table,
            array(
                'status' => 'completed',
                'served_at' => current_time('mysql')
            ),
            array('id' => $queue_id)
        );
        
        echo '<div class="notice notice-success"><p>服务已完成</p></div>';
    }
    ?>
    
    <div class="wrap">
        <h1>排队叫号管理</h1>
        
        <div class="queue-management-dashboard">
            <!-- 服务窗口状态 -->
            <div class="service-points-status">
                <h2>服务窗口状态</h2>
                <div class="service-points-grid">
                    <?php foreach ($service_points as $point): 
                        // 获取当前窗口状态
                        $current_queue = $wpdb->get_row($wpdb->prepare(
                            "SELECT q.*, a.customer_name 
                             FROM $queues_table q 
                             LEFT JOIN $appointments_table a ON q.appointment_id = a.id 
                             WHERE q.service_point_id = %d 
                             AND q.status = 'called' 
                             ORDER BY q.called_at DESC 
                             LIMIT 1",
                            $point->id
                        ));
                        
                        $waiting_count = $wpdb->get_var($wpdb->prepare(
                            "SELECT COUNT(*) FROM $queues_table 
                             WHERE service_point_id = %d 
                             AND status = 'waiting'",
                            $point->id
                        ));
                    ?>
                    <div class="service-point-card">
                        <h3><?php echo esc_html($point->name); ?> (<?php echo esc_html($point->code); ?>)</h3>
                        <div class="current-serving">
                            <?php if ($current_queue): ?>
                                <p>当前服务:<?php echo esc_html($current_queue->queue_number); ?></p>
                                <p>客户:<?php echo esc_html($current_queue->customer_name); ?></p>
                                <p>等待时间:<?php echo human_time_diff(strtotime($current_queue->called_at), current_time('timestamp')); ?></p>
                                
                                <form method="post" style="display: inline;">
                                    <input type="hidden" name="queue_id" value="<?php echo $current_queue->id; ?>">
                                    <button type="submit" name="complete_service" class="button button-primary">
                                        完成服务
                                    </button>
                                </form>
                            <?php else: ?>
                                <p>窗口空闲</p>
                            <?php endif; ?>
                        </div>
                        
                        <div class="waiting-info">
                            <p>等待人数:<?php echo $waiting_count; ?></p>
                            
                            <form method="post">
                                <input type="hidden" name="service_point_id" value="<?php echo $point->id; ?>">
                                <button type="submit" name="call_next" class="button">
                                    叫下一个号
                                </button>
                            </form>
                        </div>
                    </div>
                    <?php endforeach; ?>
                </div>
            </div>
            
            <!-- 实时排队队列 -->
            <div class="real-time-queues">
                <h2>实时排队队列</h2>
                <table class="wp-list-table widefat fixed striped">
                    <thead>
                        <tr>
                            <th>排队号码</th>
                            <th>客户姓名</th>
                            <th>服务项目</th>
                            <th>服务窗口</th>
                            <th>排队位置</th>
                            <th>预计等待</th>
                            <th>状态</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php
                        $queues = $wpdb->get_results("
                            SELECT q.*, a.customer_name, s.post_title as service_name, sp.name as point_name
                            FROM $queues_table q
                            LEFT JOIN $appointments_table a ON q.appointment_id = a.id
                            LEFT JOIN {$wpdb->posts} s ON a.service_id = s.ID
                            LEFT JOIN $service_points_table sp ON q.service_point_id = sp.id
                            WHERE q.status IN ('waiting', 'called')
                            ORDER BY 
                                CASE q.status 
                                    WHEN 'called' THEN 1 
                                    WHEN 'waiting' THEN 2 
                                    ELSE 3 
                                END,
                                q.position ASC
                            LIMIT 50
                        ");
                        
                        foreach ($queues as $queue):
                            $wait_time = $queue->estimated_wait_time > 0 ? 
                                round($queue->estimated_wait_time / 60) . '分钟' : '计算中';
                        ?>
                        <tr>
                            <td><?php echo esc_html($queue->queue_number); ?></td>
                            <td><?php echo esc_html($queue->customer_name); ?></td>
                            <td><?php echo esc_html($queue->service_name); ?></td>
                            <td><?php echo esc_html($queue->point_name); ?></td>
                            <td><?php echo $queue->position; ?></td>
                            <td><?php echo $wait_time; ?></td>
                            <td>
                                <span class="status-badge status-<?php echo $queue->status; ?>">
                                    <?php 
                                    $status_labels = array(
                                        'waiting' => '等待中',
                                        'called' => '已叫号',
                                        'completed' => '已完成'
                                    );
                                    echo $status_labels[$queue->status] ?? $queue->status;
                                    ?>
                                </span>
                            </td>
                            <td>
                                <?php if ($queue->status == 'waiting'): ?>
                                <form method="post" style="display: inline;">
                                    <input type="hidden" name="queue_id" value="<?php echo $queue->id; ?>">
                                    <input type="hidden" name="service_point_id" value="<?php echo $queue->service_point_id; ?>">
                                    <button type="submit" name="call_now" class="button button-small">
                                        立即叫号
                                    </button>
                                </form>
                                <?php endif; ?>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
            
            <!-- 叫号历史 -->
            <div class="call-history">
                <h2>今日叫号历史</h2>
                <?php
                $today = current_time('Y-m-d');
                $history = $wpdb->get_results($wpdb->prepare(
                    "SELECT ch.*, q.queue_number, a.customer_name, sp.name as point_name
                     FROM {$wpdb->prefix}call_history ch
                     LEFT JOIN $queues_table q ON ch.queue_id = q.id
                     LEFT JOIN $appointments_table a ON q.appointment_id = a.id
                     LEFT JOIN $service_points_table sp ON ch.service_point_id = sp.id
                     WHERE DATE(ch.called_at) = %s
                     ORDER BY ch.called_at DESC
                     LIMIT 20",
                    $today
                ));
                ?>
                
                <table class="wp-list-table widefat fixed striped">
                    <thead>
                        <tr>
                            <th>时间</th>
                            <th>排队号码</th>
                            <th>客户姓名</th>
                            <th>服务窗口</th>
                            <th>操作员</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($history as $record): 
                            $operator = get_userdata($record->operator_id);
                        ?>
                        <tr>
                            <td><?php echo date('H:i:s', strtotime($record->called_at)); ?></td>
                            <td><?php echo esc_html($record->queue_number); ?></td>
                            <td><?php echo esc_html($record->customer_name); ?></td>
                            <td><?php echo esc_html($record->point_name); ?></td>
                            <td><?php echo $operator ? esc_html($operator->display_name) : '系统'; ?></td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    
    <style>
    .service-points-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        gap: 20px;
        margin-bottom: 30px;
    }
    
    .service-point-card {
        border: 1px solid #ddd;
        border-radius: 8px;
        padding: 15px;
        background: #fff;
    }
    
    .service-point-card h3 {
        margin-top: 0;
        border-bottom: 2px solid #0073aa;
        padding-bottom: 10px;
    }
    
    .current-serving {
        background: #f0f8ff;
        padding: 10px;
        border-radius: 4px;
        margin-bottom: 15px;
    }
    
    .status-badge {
        display: inline-block;
        padding: 3px 8px;
        border-radius: 3px;
        font-size: 12px;
        font-weight: bold;
    }
    
    .status-waiting {
        background: #ffeb3b;
        color: #333;
    }
    
    .status-called {
        background: #4caf50;
        color: white;
    }
    
    .status-completed {
        background: #9e9e9e;
        color: white;
    }
    </style>
    <?php
}

第六章:实时通信与状态更新

6.1 WebSocket服务器实现

// WebSocket服务器类
class QueueWebSocketServer {
    private $server;
    private $clients = [];
    private $rooms = [];
    
    public function __construct($host = '0.0.0.0', $port = 8080) {
        $this->server = new SwooleWebSocketServer($host, $port);
        
        $this->server->on('open', [$this, 'onOpen']);
        $this->server->on('message', [$this, 'onMessage']);
        $this->server->on('close', [$this, 'onClose']);
        
        // 定时推送队列更新
        $this->server->tick(5000, [$this, 'broadcastQueueUpdates']);
    }
    
    public function onOpen($server, $request) {
        $client_id = $request->fd;
        $this->clients[$client_id] = [
            'id' => $client_id,
            'room' => null,
            'type' => 'client' // client, display, admin
        ];
        
        echo "客户端 {$client_id} 已连接n";
    }
    
    public function onMessage($server, $frame) {
        $data = json_decode($frame->data, true);
        $client_id = $frame->fd;
        
        if (!$data || !isset($data['action'])) {
            return;
        }
        
        switch ($data['action']) {
            case 'join_room':
                $this->joinRoom($client_id, $data['room']);
                break;
                
            case 'subscribe_queue':
                $this->subscribeQueue($client_id, $data['queue_number']);
                break;
                
            case 'admin_command':
                $this->handleAdminCommand($client_id, $data);
                break;
        }
    }
    
    public function onClose($server, $fd) {
        if (isset($this->clients[$fd])) {
            $client = $this->clients[$fd];
            
            // 从房间中移除
            if ($client['room'] && isset($this->rooms[$client['room']])) {
                $index = array_search($fd, $this->rooms[$client['room']]);
                if ($index !== false) {
                    array_splice($this->rooms[$client['room']], $index, 1);
                }
            }
            
            unset($this->clients[$fd]);
            echo "客户端 {$fd} 已断开连接n";
        }
    }
    
    private function joinRoom($client_id, $room) {
        $this->clients[$client_id]['room'] = $room;
        
        if (!isset($this->rooms[$room])) {
            $this->rooms[$room] = [];
        }
        
        if (!in_array($client_id, $this->rooms[$room])) {
            $this->rooms[$room][] = $client_id;
        }
        
        // 发送欢迎消息
        $welcome = [
            'type' => 'system',
            'message' => "已加入房间: {$room}",
            'timestamp' => time()
        ];
        
        $this->server->push($client_id, json_encode($welcome));
    }
    
    private function subscribeQueue($client_id, $queue_number) {
        $this->clients[$client_id]['queue_number'] = $queue_number;
        
        // 发送当前队列状态
        $queue_status = $this->getQueueStatus($queue_number);
        $this->server->push($client_id, json_encode([
            'type' => 'queue_status',
            'data' => $queue_status
        ]));
    }
    
    private function handleAdminCommand($client_id, $data) {
        if ($this->clients[$client_id]['type'] !== 'admin') {
            return;
        }
        
        switch ($data['command']) {
            case 'call_number':
                $this->broadcastCallNumber($data['queue_number'], $data['service_point']);
                break;
                
            case 'update_queue':
                $this->broadcastQueueUpdate();
                break;
        }
    }
    
    public function broadcastQueueUpdates() {
        global $wpdb;
        
        $queues_table = $wpdb->prefix . 'queues';
        
        // 获取需要更新的队列信息
        $active_queues = $wpdb->get_results("
            SELECT queue_number, position, estimated_wait_time, status
            FROM $queues_table 
            WHERE status IN ('waiting', 'called')
            AND updated_at >= DATE_SUB(NOW(), INTERVAL 5 MINUTE)
        ");
        
        if (empty($active_queues)) {
            return;
        }
        
        $update_data = [
            'type' => 'queue_update',
            'data' => $active_queues,
            'timestamp' => time()
        ];
        
        // 广播给所有客户端
        foreach ($this->clients as $client_id => $client) {
            if ($client['type'] === 'client') {
                $this->server->push($client_id, json_encode($update_data));
            }
        }
        
        // 广播给显示屏幕
        if (isset($this->rooms['display'])) {
            $display_data = $this->getDisplayData();
            foreach ($this->rooms['display'] as $display_client) {
                $this->server->push($display_client, json_encode([
                    'type' => 'display_update',
                    'data' => $display_data
                ]));
            }
        }
    }
    
    private function broadcastCallNumber($queue_number, $service_point) {
        $call_data = [
            'type' => 'call_number',
            'queue_number' => $queue_number,
            'service_point' => $service_point,
            'timestamp' => time()
        ];
        
        // 通知特定客户
        foreach ($this->clients as $client_id => $client) {
            if (isset($client['queue_number']) && $client['queue_number'] === $queue_number) {
                $this->server->push($client_id, json_encode($call_data));
            }
        }
        
        // 广播给显示屏幕
        if (isset($this->rooms['display'])) {
            foreach ($this->rooms['display'] as $display_client) {
                $this->server->push($display_client, json_encode($call_data));
            }
        }
        
        // 记录到数据库
        global $wpdb;
        $wpdb->insert($wpdb->prefix . 'call_notifications', [
            'queue_number' => $queue_number,
            'service_point' => $service_point,
            'called_at' => current_time('mysql')
        ]);
    }
    
    private function getQueueStatus($queue_number) {
        global $wpdb;
        
        $queues_table = $wpdb->prefix . 'queues';
        $appointments_table = $wpdb->prefix . 'appointments';
        
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5112.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部