实战教学:为网站集成在线预约排队与叫号系统——通过WordPress代码二次开发实现常用互联网小工具功能
引言:数字化时代下的服务升级需求
在当今快节奏的数字化社会中,无论是医疗机构、教育机构、政府服务大厅,还是餐饮、美容、维修等商业服务场所,排队等待已成为客户体验中最令人不满的环节之一。传统的排队方式不仅消耗客户宝贵时间,也增加了服务场所的管理难度和人力成本。随着互联网技术的普及,在线预约排队与叫号系统应运而生,成为提升服务效率、优化客户体验的重要工具。
对于大多数中小型企业和机构而言,定制开发一套完整的预约排队系统成本高昂,维护复杂。而WordPress作为全球最流行的内容管理系统,以其强大的扩展性和灵活性,为我们提供了一个经济高效的解决方案。本文将深入探讨如何通过WordPress程序的代码二次开发,为网站集成一套功能完善的在线预约排队与叫号系统,实现这一常用互联网小工具功能。
第一章:系统需求分析与设计规划
1.1 业务场景分析
在开始技术实现之前,我们首先需要明确系统的使用场景和功能需求。一个典型的在线预约排队与叫号系统应包含以下核心功能:
-
客户端功能:
- 服务项目浏览与选择
- 预约时间选择与提交
- 排队号码获取与状态查询
- 实时排队位置提醒
- 预约取消与改期
-
管理端功能:
- 预约申请审核与管理
- 排队队列实时监控
- 叫号操作与控制
- 服务窗口/人员管理
- 数据统计与分析报表
-
现场显示功能:
- 当前叫号信息展示
- 等待队列信息展示
- 服务窗口状态显示
1.2 技术架构设计
基于WordPress的二次开发,我们采用以下技术架构:
- 前端展示层:使用WordPress主题模板系统,结合HTML5、CSS3和JavaScript(特别是AJAX技术)实现用户界面
- 业务逻辑层:通过自定义Post Type、Taxonomy和Meta Box构建数据模型,利用Action和Filter钩子扩展核心功能
- 数据持久层:利用WordPress数据库结构,创建自定义数据表存储预约和排队信息
- 实时通信层:采用WebSocket或轮询技术实现排队状态的实时更新
- 外部接口层:集成短信/邮件通知API,提供状态提醒服务
第二章:WordPress开发环境搭建与基础配置
2.1 开发环境准备
在开始开发之前,我们需要搭建一个适合WordPress二次开发的环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:下载最新版WordPress,完成基础安装
-
开发工具配置:
- 代码编辑器: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';
