1. 医院排队叫号系统的技术选型思考
在医院门诊大厅,每天早晨七点就开始排起长队。导诊台护士手工发号、患者挤在诊室门口张望、医生扯着嗓子喊名字的场景,相信大家都不陌生。这种传统方式不仅效率低下,还容易引发插队纠纷。我去年参与了三甲医院排队系统的升级项目,从零开始用PHP框架重构了整套系统。当时在ThinkPHP和Laravel之间的选择,确实费了一番功夫。
ThinkPHP就像医院里的"全科医生"——开箱即用,对常见需求都有现成解决方案。它的中文文档齐全,连分诊叫号这种业务模块都能在官方扩展库找到近似实现。而Laravel更像是带着精密仪器的"专科专家",需要更专业的技术团队才能发挥其威力。我们最终选择双框架混合架构:用ThinkPHP快速搭建前台叫号展示页面,用Laravel构建后台的复杂排队算法引擎。
关键决策点:当系统需要处理突发性高并发(比如上午挂号高峰)时,Laravel的队列服务配合Redis能更稳定地分配叫号资源;而ThinkPHP的模板引擎让前端大屏展示开发效率提升40%。
2. 核心功能模块拆解与实现
2.1 挂号排队引擎设计
排队逻辑远不是简单的先到先得。我们实现了三级优先级机制:
- 急诊患者自动插队(红色警报级)
- 预约患者按时间段浮动排序(动态权重计算)
- 普通挂号患者按签到时间排序
php复制// Laravel服务端排队算法片段
class QueueService {
public function calculatePriority($patient) {
$base = strtotime($patient->check_in_time);
if ($patient->is_emergency) {
return $base - 3600 * 24; // 急诊提前24小时权重
}
if ($patient->appointment_time) {
$diff = abs(time() - strtotime($patient->appointment_time));
return $base - min($diff, 3600); // 预约时间差补偿
}
return $base;
}
}
2.2 实时叫号推送方案
传统轮询方式在200+并发时就会让服务器不堪重负。我们最终采用ThinkPHP的GatewayWorker实现WebSocket推送,关键配置:
php复制// ThinkPHP的worker配置
$gateway = new Gateway("Websocket://0.0.0.0:7272");
$gateway->name = 'HospitalQueue';
$gateway->count = 4; // 根据CPU核心数设置
$gateway->onConnect = function($connection) {
$connection->send(json_encode(['type'=>'welcome']));
};
实测数据显示,WebSocket方案比AJAX轮询减少85%的服务器负载,在上午就诊高峰时段(约3000次叫号/小时)保持稳定。
2.3 多终端同步显示
从诊室门口的液晶屏到护士站的电脑,再到患者微信小程序,状态同步是个大挑战。我们设计了一套基于Redis的发布/订阅机制:
- 叫号事件触发Laravel事件
- 事件广播到Redis频道
- 各终端通过订阅频道获取更新
- ThinkPHP前端消费消息并渲染
bash复制# Redis消息示例
PUBLISH queue_update '{"room":"301","current":"A102","next":["A103","A104"]}'
3. 双框架融合的实践技巧
3.1 共享会话管理
两个框架的session机制不同,我们通过中间件实现会话同步:
php复制// Laravel端中间件
class SyncSession {
public function handle($request, $next) {
if ($tp_session = $request->cookie('PHPSESSID')) {
session_id($tp_session);
}
return $next($request);
}
}
3.2 统一日志收集
在项目根目录创建logs/queue.log,两个框架都配置写入同一文件:
php复制// ThinkPHP配置
'log' => [
'path' => '../logs/queue.log'
]
// Laravel配置
'channels' => [
'queue' => [
'driver' => 'single',
'path' => storage_path('../logs/queue.log')
]
]
3.3 数据库设计要点
排队系统核心表结构优化经验:
- 候诊队列表添加composite index (status, priority_score)
- 叫号历史表按月分表(2023_07_queue_history)
- 使用MySQL的JSON字段存储动态患者属性
sql复制CREATE TABLE `queue` (
`id` bigint PRIMARY KEY AUTO_INCREMENT,
`patient_id` varchar(20) NOT NULL,
`status` enum('waiting','called','completed') DEFAULT 'waiting',
`priority_score` int DEFAULT 0,
`extra_info` json DEFAULT NULL,
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
INDEX `status_priority` (`status`, `priority_score`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4. 踩坑实录与性能优化
4.1 内存泄漏排查
上线两周后,服务器在凌晨定时任务期间频繁崩溃。通过XHProf分析发现:
- Laravel队列worker未正确释放患者病历PDF生成资源
- ThinkPHP的缓存驱动在长连接时积累未关闭句柄
解决方案:
- 在队列任务类中添加__destruct()释放资源
- 改用Redis替代文件缓存
- 增加crontab定时重启worker
php复制// 修正后的队列任务
class GeneratePDF implements ShouldQueue {
private $pdf;
public function __destruct() {
if ($this->pdf) {
$this->pdf->close();
}
}
}
4.2 高并发压力测试
使用JMeter模拟早高峰场景时发现的问题及优化:
| 问题现象 | 优化方案 | 效果提升 |
|---|---|---|
| 叫号延迟8秒 | 增加Redis连接池 | 降至<1秒 |
| 数据库CPU100% | 添加队列缓存层 | 负载降低60% |
| WebSocket断连 | 调整Gateway心跳间隔 | 稳定性提升至99.9% |
4.3 防插队机制实现
实际运营中发现有患者篡改前端JS伪造优先号。我们增加了三重验证:
- 前端:WebSocket消息HMAC签名
- 后端:Laravel策略检查
- 数据库:触发器校验状态流转合法性
php复制// Laravel策略类
class QueuePolicy {
public function call(Staff $staff, Queue $queue) {
return $queue->status == 'waiting'
&& $queue->clinic_id == $staff->clinic_id
&& $queue->priority_score <= $this->calculateMaxPriority();
}
}
5. 扩展功能开发建议
5.1 智能分诊辅助
通过历史数据分析,我们后来增加了自动分诊建议:
- 症状关键词匹配(自然语言处理)
- 科室负载均衡算法
- 医生专长权重计算
python复制# 用Python微服务实现(与PHP通过gRPC交互)
def suggest_department(symptoms):
model = load_keras_model('triage.h5')
return model.predict(preprocess_text(symptoms))
5.2 移动端集成方案
患者端小程序开发要点:
- 叫号状态变更推送(微信模板消息)
- 排队位置预估算法
- 过号自动延后机制
javascript复制// 微信小程序订阅示例
wx.requestSubscribeMessage({
tmplIds: ['叫号提醒模板ID'],
success(res) { console.log('订阅成功') }
})
5.3 数据可视化大屏
使用ECharts实现的院长驾驶舱:
- 实时候诊人数热力图
- 科室效率对比雷达图
- 历史流量预测曲线
javascript复制// 实时数据获取
setInterval(() => {
fetch('/api/queue-stats').then(res => {
myChart.setOption(updateOptions(res.data));
});
}, 5000);
在项目上线半年后,医院门诊投诉量下降37%,患者平均等待时间从52分钟缩短至19分钟。有个细节让我印象深刻:有位老奶奶特意来信息科道谢,说现在终于能坐着等叫号,不用站着排队了。这种技术带来的真实改变,才是我们开发者最大的成就感。
