1. 项目背景与核心需求
体检中心导检排队管理系统是医疗机构信息化建设的重要组成部分。随着健康体检需求的快速增长,传统人工排队方式已无法满足现代体检中心的高效运转需求。根据某三甲医院体检中心的数据统计,采用信息化排队系统后,平均候检时间缩短了47%,客户满意度提升了32个百分点。
这个基于SpringBoot的毕业设计项目,旨在解决以下几个核心痛点:
- 流程混乱:体检者经常不清楚下一步该去哪个科室,导致走廊拥堵和资源浪费
- 等待不均:热门科室(如B超)排队过长,而普通科室(如身高体重)却闲置
- 数据孤岛:各科室检查数据分散,无法实时汇总生成最终报告
- 管理低效:人工统计各科室工作量耗时费力,难以优化资源配置
2. 系统架构设计
2.1 技术选型依据
选择SpringBoot作为基础框架主要基于以下考虑:
- 快速开发:自动配置和起步依赖大幅减少XML配置
- 内嵌容器:无需额外部署Tomcat,简化开发测试流程
- 生态丰富:与MyBatis、Redis等常用组件无缝集成
- 监控完善:Actuator提供健康检查、指标监控等生产级功能
技术栈组成:
mermaid复制graph TD
A[SpringBoot 2.7.x] --> B[持久层: MyBatis-Plus]
A --> C[缓存: Redis]
A --> D[安全: Spring Security]
A --> E[前端: Thymeleaf+Bootstrap]
A --> F[消息队列: RabbitMQ]
2.2 核心业务流程设计
系统采用状态机模式管理体检流程:
java复制public enum CheckupStatus {
REGISTERED, // 已登记
WAITING, // 待检
IN_PROGRESS, // 检查中
COMPLETED, // 已完成
CANCELLED // 已取消
}
关键业务时序:
- 用户通过小程序/自助机挂号
- 系统根据科室负载智能分配队列
- 导检屏实时显示叫号信息
- 医生端标记检查完成状态
- 数据自动汇总生成报告
3. 核心功能实现细节
3.1 智能排队算法
采用动态权重分配策略,考虑因素包括:
- 科室当前等待人数
- 检查平均耗时(B超约15分钟,抽血约3分钟)
- 特殊优先级(VIP、老年人等)
- 项目依赖关系(空腹项目需优先安排)
核心算法实现:
java复制public class QueueStrategy {
// 科室权重计算公式
private double calculateDepartmentWeight(Department dept) {
double base = 1.0;
double waitFactor = Math.log(dept.getWaitingCount() + 1) * 0.5;
double timeFactor = dept.getAvgMinutes() / 60.0;
return base + waitFactor + timeFactor;
}
// 优先级调整
public void adjustPriority(Ticket ticket) {
if(ticket.getUser().isVip()) {
ticket.setPriority(ticket.getPriority() * 1.5);
}
// 其他调整规则...
}
}
3.2 实时通知机制
采用WebSocket+Redis Pub/Sub实现多终端同步:
- 前端建立WebSocket连接
- 后端使用Redis的keyspace notifications
- 消息格式设计:
json复制{
"eventType": "CALL_NEXT",
"department": "B超室",
"ticketNo": "A102",
"counterNo": "3号窗口",
"timestamp": 1689234567890
}
关键配置(application.yml):
yaml复制spring:
redis:
host: 127.0.0.1
port: 6379
websocket:
allowed-origins: "*"
endpoint: /queue-notify
4. 数据库设计要点
4.1 核心表结构
sql复制CREATE TABLE `t_checkup_ticket` (
`id` bigint NOT NULL AUTO_INCREMENT,
`ticket_no` varchar(20) NOT NULL COMMENT '票号格式: A001',
`user_id` bigint NOT NULL,
`department_id` int NOT NULL,
`status` enum('WAITING','IN_PROGRESS','COMPLETED') DEFAULT 'WAITING',
`priority` tinyint DEFAULT 5 COMMENT '1-9优先级',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_ticket_no` (`ticket_no`),
KEY `idx_dept_status` (`department_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 性能优化实践
- 读写分离:查询走从库,更新走主库
- 热点数据缓存:使用Redis缓存科室实时队列
- 批量插入:MyBatis的foreach批量插入体检项目
- 索引优化:为status、department_id等字段建立组合索引
5. 典型问题解决方案
5.1 并发取号问题
使用Redis原子操作防止超发:
java复制public String generateTicketNo() {
String datePrefix = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
Long seq = redisTemplate.opsForValue().increment("ticket:seq:" + datePrefix);
return "A" + String.format("%03d", seq % 1000);
}
5.2 检查项依赖处理
使用有向无环图(DAG)建模项目依赖:
java复制public class CheckupDAG {
private Map<String, List<String>> adjacencyList = new HashMap<>();
public void addEdge(String from, String to) {
adjacencyList.computeIfAbsent(from, k -> new ArrayList<>()).add(to);
}
public List<String> getExecutionOrder() {
// 拓扑排序实现...
}
}
6. 部署与监控
6.1 生产环境配置
Docker Compose示例:
yaml复制version: '3'
services:
app:
image: health-checkup:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
6.2 监控指标采集
Spring Boot Actuator配置:
properties复制management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.tags.application=health-checkup
关键监控指标:
- 平均等待时间(histogram_checkup_wait_seconds)
- 科室吞吐量(counter_department_completed_total)
- 系统异常数(counter_errors_total)
7. 开发经验分享
7.1 排错技巧
当遇到MyBatis的UnsupportedOperationException时:
- 检查SQL语句是否包含不支持的函数
- 确认JDBC驱动版本兼容性
- 排查是否有字段类型不匹配
- 使用MyBatis的日志级别DEBUG查看完整SQL
7.2 性能调优
实测中发现的问题及解决方案:
-
问题:高峰期Redis连接超时
解决:配置连接池并增加重试机制java复制@Bean public LettuceConnectionFactory redisConnectionFactory() { LettuceClientConfiguration config = LettuceClientConfiguration.builder() .commandTimeout(Duration.ofSeconds(30)) .clientResources(ClientResources.builder().build()) .build(); return new LettuceConnectionFactory(new RedisStandaloneConfiguration(), config); } -
问题:导检屏刷新卡顿
解决:前端采用虚拟滚动技术,后端增加缓存javascript复制// Vue实现示例 <virtual-list :size="50" :remain="10" :items="queueItems"/>
这个项目让我深刻体会到,医疗信息化系统不仅需要技术实现,更要理解实际业务流程。在开发过程中,我多次到本地体检中心实地观察,发现许多在办公室想不到的细节问题,比如老年人对语音提示的依赖、导检单的易丢失问题等,这些洞察最终都转化成了系统的特色功能。
