ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SpringBoot+Vue医疗挂号系统设计与实现

SpringBoot+Vue医疗挂号系统设计与实现 1. 医疗挂号管理系统概述医疗挂号管理系统是医疗机构信息化建设的基础模块它解决了传统人工挂号模式效率低下、资源分配不均的问题。这个基于SpringBootVue的前后端分离系统采用了当前企业级开发的主流技术栈既能满足实际医院运营需求又非常适合作为计算机专业学生的毕业设计或课程设计选题。我在三甲医院信息化建设项目中参与过类似系统的开发这类系统最核心的价值在于实现了三流合一患者流、医生工作流和数据流的统一管理。通过线上挂号、分诊、叫号等功能的数字化改造能使医院门诊效率提升40%以上同时减少患者平均等待时间。2. 系统架构设计2.1 技术选型解析后端技术栈SpringBoot 2.7.x简化了传统SSM框架的复杂配置内置Tomcat服务器starter机制让依赖管理更简单MyBatis-Plus 3.5.x增强版ORM框架提供代码生成器和丰富CRUD接口Redis 6.x用于缓存热门科室信息和号源数据减轻数据库压力JWT实现无状态认证适合分布式场景前端技术栈Vue 3.x组合式API开发更灵活配合TypeScript提升代码质量Element Plus提供丰富的UI组件加速界面开发Axios处理HTTP请求内置请求拦截器ECharts 5.x可视化展示挂号量、科室流量等数据提示技术选型时特别注意版本兼容性例如SpringBoot 2.7.x与JDK 17的匹配Vue 3.x需要配套使用Vue CLI 5.x2.2 系统模块划分医疗挂号管理系统 ├── 患者端功能 │ ├── 微信小程序挂号 │ ├── 科室医生查询 │ ├── 预约挂号 │ ├── 挂号记录查询 │ └── 就诊评价 ├── 医生端功能 │ ├── 排班管理 │ ├── 叫号系统 │ ├── 病历调阅 │ └── 处方开具 └── 管理端功能 ├── 科室管理 ├── 医生管理 ├── 号源分配 ├── 数据统计 └── 系统监控3. 数据库设计与实现3.1 核心表结构患者表(patient)CREATE TABLE patient ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, openid varchar(64) DEFAULT NULL COMMENT 微信openid, name varchar(32) NOT NULL COMMENT 姓名, id_card varchar(18) NOT NULL COMMENT 身份证号, phone varchar(11) NOT NULL COMMENT 手机号, avatar varchar(255) DEFAULT NULL COMMENT 头像, status tinyint DEFAULT 1 COMMENT 状态(0:禁用 1:正常), create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_id_card (id_card), UNIQUE KEY uk_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT患者信息;号源表(schedule)CREATE TABLE schedule ( id bigint NOT NULL AUTO_INCREMENT, dept_id bigint NOT NULL COMMENT 科室ID, doctor_id bigint NOT NULL COMMENT 医生ID, work_date date NOT NULL COMMENT 排班日期, time_slot tinyint NOT NULL COMMENT 时段(1:上午 2:下午 3:晚上), total_num int NOT NULL DEFAULT 0 COMMENT 号源总数, available_num int NOT NULL DEFAULT 0 COMMENT 剩余号源, fee decimal(10,2) NOT NULL COMMENT 挂号费, status tinyint DEFAULT 1 COMMENT 状态(0:停诊 1:正常), PRIMARY KEY (id), KEY idx_dept_doctor (dept_id,doctor_id), KEY idx_work_date (work_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT排班号源表;3.2 关键业务表关系主要业务关系患者与挂号记录一对多医生与排班一对多科室与医生一对多挂号记录与排班多对一4. 核心功能实现4.1 预约挂号流程RestController RequestMapping(/api/registration) public class RegistrationController { Autowired private ScheduleService scheduleService; Autowired private RegistrationService registrationService; PostMapping public Result register(RequestBody RegistrationDTO dto) { // 1. 校验号源是否可用 Schedule schedule scheduleService.getById(dto.getScheduleId()); if (schedule null || schedule.getAvailableNum() 0) { return Result.fail(号源已约满); } // 2. 分布式锁防止超卖 String lockKey reg_lock: dto.getScheduleId(); try { boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS); if (!locked) { return Result.fail(当前预约人数过多请重试); } // 3. 创建挂号记录 Registration registration new Registration(); BeanUtils.copyProperties(dto, registration); registration.setStatus(0); // 待支付 registration.setOutTradeNo(IdUtil.simpleUUID()); registrationService.save(registration); // 4. 扣减库存 scheduleService.deductAvailableNum(dto.getScheduleId()); return Result.ok(registration); } finally { redisTemplate.delete(lockKey); } } }4.2 叫号系统实现前端关键代码(Vue3 WebSocket)// 建立WebSocket连接 const socket new WebSocket(wss://${location.host}/api/call) // 监听叫号消息 socket.onmessage (event) { const data JSON.parse(event.data) if (data.type CALL_NEXT) { // 更新叫号显示 currentNumber.value data.number // 播放语音提示 playAudio(请${data.number}号到${data.room}就诊) } } // 医生点击下一位按钮 const callNext () { socket.send(JSON.stringify({ doctorId: doctor.value.id, deptId: doctor.value.deptId })) }后端WebSocket处理ServerEndpoint(/api/call) Component public class CallEndpoint { private static ConcurrentHashMapString, Session sessions new ConcurrentHashMap(); OnOpen public void onOpen(Session session) { String doctorId session.getRequestParameterMap().get(doctorId).get(0); sessions.put(doctorId, session); } OnMessage public void onMessage(String message, Session session) { JSONObject json JSON.parseObject(message); String doctorId json.getString(doctorId); String deptId json.getString(deptId); // 查询下一个待就诊患者 Registration next registrationService.getNextRegistration(deptId, doctorId); if (next ! null) { // 广播叫号信息 broadcast(next.getQueueNumber(), next.getRoomNumber()); // 更新状态为就诊中 registrationService.updateStatus(next.getId(), 2); } } private void broadcast(String number, String room) { JSONObject message new JSONObject(); message.put(type, CALL_NEXT); message.put(number, number); message.put(room, room); sessions.values().forEach(session - { try { session.getBasicRemote().sendText(message.toJSONString()); } catch (IOException e) { log.error(发送消息失败, e); } }); } }5. 典型问题与解决方案5.1 号源超卖问题问题现象高并发场景下同一号源被多个患者同时预约成功解决方案使用Redis分布式锁如代码示例所示数据库乐观锁Update(update schedule set available_num available_num - 1 where id #{scheduleId} and available_num 0) int deductAvailableNum(Param(scheduleId) Long scheduleId);前端限制提交按钮防重复点击5.2 定时放号任务需求背景每天凌晨自动释放未来7天的号源SpringBoot定时任务实现Slf4j Component public class ScheduleReleaseJob { Autowired private ScheduleService scheduleService; // 每天0点执行 Scheduled(cron 0 0 0 * * ?) public void releaseSchedules() { log.info(开始执行号源释放任务); LocalDate startDate LocalDate.now().plusDays(1); LocalDate endDate LocalDate.now().plusDays(7); // 批量生成未来7天的号源 ListSchedule schedules new ArrayList(); ListDoctor doctors doctorService.listActiveDoctors(); for (LocalDate date startDate; !date.isAfter(endDate); date date.plusDays(1)) { for (Doctor doctor : doctors) { // 上午号源 schedules.add(buildSchedule(doctor, date, 1, 20)); // 下午号源 schedules.add(buildSchedule(doctor, date, 2, 15)); } } scheduleService.saveBatch(schedules); log.info(号源释放完成共生成{}条记录, schedules.size()); } private Schedule buildSchedule(Doctor doctor, LocalDate date, int timeSlot, int totalNum) { Schedule schedule new Schedule(); schedule.setDeptId(doctor.getDeptId()); schedule.setDoctorId(doctor.getId()); schedule.setWorkDate(date); schedule.setTimeSlot(timeSlot); schedule.setTotalNum(totalNum); schedule.setAvailableNum(totalNum); schedule.setFee(doctor.getRegistrationFee()); schedule.setStatus(1); return schedule; } }5.3 跨域问题处理Vue开发环境配置// vue.config.js module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } }SpringBoot跨域配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .maxAge(3600); } }6. 项目部署指南6.1 后端部署Docker部署示例# Dockerfile FROM openjdk:17-jdk-slim VOLUME /tmp COPY target/medical-registration-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT [java,-jar,/app.jar]关键启动参数java -jar -Dspring.profiles.activeprod \ -Dserver.port8080 \ -Dspring.datasource.urljdbc:mysql://mysql:3306/medical?useSSLfalse \ -Dspring.datasource.usernameroot \ -Dspring.datasource.password123456 \ app.jar6.2 前端部署Nginx配置示例server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }7. 毕设扩展建议智能推荐科室基于患者症状描述使用NLP技术推荐合适科室候诊时间预测根据历史数据预测当前患者的预计等待时间人脸识别签到对接人脸识别API实现刷脸签到医保对接实现与医保系统的对接需模拟接口大数据分析使用Spark分析挂号数据发现就诊规律我在实际开发中发现挂号系统的并发控制是最容易出问题的环节特别是在上午8-10点的挂号高峰期。建议在毕设演示时使用JMeter模拟至少100并发用户进行压力测试这能充分体现系统的健壮性。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进