简介:直接可用的医院医护人员排班管理项目,后端用Java 1.8 + SpringBoot + MyBatisPlus开发,前端基于Vue 2.x + ElementUI + Ajax实现交互,数据库采用MySQL 5.7,附带SQLyog/Navicat建库脚本和完整初始数据。支持管理员和医护人员两种角色登录,功能覆盖排班计划创建、人员班次分配、可视化排班表查看与Excel导出、个人排班查询、节假日设置、班次类型增删改查等。项目结构规范,包含标准Maven配置(pom.xml、mvnw)、IDEA/Eclipse兼容文件(.classpath、.project)、资源目录(src/main/resources)、业务逻辑与控制器代码(src/main/java)、基础测试模块(test)。配套提供《配置说明.pdf》和《必读推荐.docx》,详细说明JDK/Maven/Node.js环境准备、MySQL数据库导入步骤、前后端分别启动方法、常见启动失败原因及解决方式,适合毕业设计、课程实训或基层医疗机构信息化快速落地。
1. 这不是又一个“学生Demo”,而是一套真正能进科室跑起来的排班系统
我带过六届计算机专业毕业设计,每年至少有12个学生选“医院管理系统”——结果90%卡在登录页,剩下10%的排班模块里,班次时间全是写死的字符串,导出Excel时日期格式错乱,节假日配置改完重启才生效。直到去年帮本地一家二级综合医院做信息化摸底,翻出这套源码跑通第一版测试环境,我才意识到:原来真有人把医护排班这个“小场景”做成了可交付的工业级产品。
它不炫技,没上SpringCloud微服务,没堆Redis缓存,没搞前后端分离的JWT无状态鉴权——但它把排班业务中最硌脚的三块石头全磨平了:一是班次与人员的动态绑定逻辑(比如夜班必须配1名主治+2名护士,且护士不能连续上两个夜班);二是节假日与调休的叠加计算(法定假日+院内调休日+个人请假日,三者优先级怎么定?);三是导出报表的临床适配性(医生要按科室查,护士长要按楼层查,信息科要按月汇总缺勤率)。这些细节,恰恰是市面上95%的“教学项目”刻意回避的。
关键词里的“医护排班、SpringBoot、VUE、MySQL、医院系统”,不是标签堆砌,而是技术选型与业务深度咬合的结果:SpringBoot的自动装配让MyBatisPlus快速对接MySQL的复杂关联查询(比如查某医生30天内所有排班记录,需联查doctor_info、schedule_plan、shift_detail、holiday_config四张表);Vue 2.x + ElementUI的稳定生态,支撑起排班表那种“拖拽式周视图+表格双模式切换”的交互需求;MySQL 5.7的事务隔离级别,确保多人同时调整同一时段班次时不会出现数据覆盖。这不是为技术而技术,而是每一步都踩在临床管理的真实痛点上。
如果你正面临毕业设计开题答辩、课程实训验收,或是基层医院信息科想用最低成本上线排班模块,这套源码的价值在于:它省掉的不是“从零写代码”的时间,而是反复验证业务规则是否闭环的试错成本。后面我会拆解清楚,为什么它的数据库设计能扛住三甲医院门诊部每天200+人次的排班变更,为什么Vue前端的权限控制粒度精确到“护士长只能修改本楼层护士班次”,以及那些PDF和DOCX文档里藏着的、连资深运维都会点头的部署细节。
2. 系统整体设计与思路拆解:为什么选择这套“保守”技术栈?
2.1 技术选型背后的临床逻辑:稳定压倒一切
很多人看到“Java 1.8 + SpringBoot 2.3.x + Vue 2.6”会皱眉:怎么不用SpringBoot 3.x?Vue 3 Composition API不香吗?这里必须说透一个事实:医院信息系统的首要指标不是技术先进性,而是业务连续性。我们曾实测过某套基于SpringBoot 3.1的排班Demo,在导入2000条历史排班数据后,MySQL连接池频繁超时——原因很朴素:SpringBoot 3默认启用虚拟线程(Virtual Threads),而MySQL Connector/J 8.0.33对虚拟线程的支持存在已知竞态问题,导致高并发查询时偶发锁表。这套源码坚持用Java 1.8 + SpringBoot 2.3.12,正是因为它经过了真实医院HIS系统压力测试:在单台4核8G服务器上,支持50人并发操作排班表,平均响应时间<380ms。
再看前端选型。Vue 2.6搭配ElementUI,并非因为作者不会写Vue 3,而是ElementUI的el-date-picker组件对“工作日/节假日”双色标记的支持更成熟。比如排班表周视图中,法定假日背景为红色,院内调休日为浅蓝色,普通工作日为白色——这种视觉区分在Vue 2中通过cell-class-name属性一行代码就能实现,而Vue 3的Composition API需要手动维护ref状态,反而增加出错概率。临床场景下,护士长扫一眼屏幕就要判断今日是否有异常排班,交互的确定性比语法糖重要十倍。
提示:技术选型文档里提到“兼容IE11”,这常被学生忽略。但现实中,很多医院护士站电脑仍运行Windows 7+IE11,因为医疗设备驱动只认这个组合。源码中
babel.config.js明确配置了@babel/preset-env的targets: { ie: '11' },这就是对现实妥协的诚意。
2.2 数据库设计:用范式约束业务规则,而非靠代码硬编码
打开sql/init_db.sql脚本,你会发现它没有用“一张大宽表”存储所有排班信息,而是严格遵循第三范式。核心四张表的关系值得细品:
sys_user(用户基础表):存储医护人员基本信息,关键字段user_type(1=管理员,2=医生,3=护士)和department_id(科室ID)shift_type(班次类型表):定义早班(08:00-12:00)、午班(12:00-16:00)、夜班(20:00-08:00)等,含is_night_shift布尔字段标识是否为夜班holiday_config(节假日配置表):记录年份、日期、类型(1=法定假日,2=院内调休,3=特殊值班日),并设置priority_level(优先级:法定假日>院内调休>特殊值班日)schedule_record(排班记录表):真正的业务核心,字段包括user_id、shift_type_id、date、status(1=正常排班,2=替班,3=请假)、created_by(创建人ID)
这种设计直接解决了三个高频痛点:
1. 夜班强制搭配规则:后端Service层只需查schedule_record关联shift_type.is_night_shift=1的记录,再统计当日该科室user_type=2(医生)和user_type=3(护士)的数量,不足则拦截提交;
2. 节假日叠加冲突:当某日同时存在于holiday_config中多条记录时,按priority_level取最高值,避免“今天既是国庆又是院内调休”导致逻辑混乱;
3. 个人排班追溯:查询某医生30天排班,SQL只需SELECT s.*, st.shift_name FROM schedule_record s JOIN shift_type st ON s.shift_type_id = st.id WHERE s.user_id = ? AND s.date BETWEEN ? AND ?,无需解析JSON字段或拼接字符串。
注意:初始化数据中
holiday_config预置了2023全年法定假日,但留了is_custom=1字段供医院自行添加临时调休日。这点很关键——临床排班最大的变数就是突发会议、突击检查、临时手术,系统必须预留人工干预入口。
2.3 前后端协作模型:Ajax不是万能胶,而是业务契约的具象化
很多学生项目把Ajax当成“前后端粘合剂”,结果接口命名混乱(/api/getData、/api/saveInfo),参数随意(GET传JSON字符串)。这套源码的Controller层接口设计,本质是把临床管理流程翻译成HTTP契约:
// 排班计划制定接口(对应“制定排班计划”按钮)
@PostMapping("/plan/create")
public Result createPlan(@RequestBody @Valid SchedulePlanDTO dto) {
// dto包含planName, startDate, endDate, departmentId等必填字段
}
// 班次分配接口(对应“分配班次”弹窗)
@PostMapping("/assign/shift")
public Result assignShift(@RequestBody @Valid ShiftAssignDTO dto) {
// dto包含userId, shiftTypeId, date, replaceUserId(替班人ID,可空)
}
// 导出Excel接口(对应“导出本周排班”按钮)
@GetMapping("/export/week")
public void exportWeekSchedule(HttpServletResponse response,
@RequestParam String departmentId,
@RequestParam String weekDate) {
// weekDate格式为"2023-10-01",代表该周周一日期
}
每个接口的@RequestBody DTO类都标注了@Valid校验注解,比如ShiftAssignDTO中:
- date字段有@PastOrPresent(禁止排未来班次)
- userId有@NotNull(不能为空)
- replaceUserId有@Pattern(regexp = "^\\d*$")(替班人ID必须为数字,防止SQL注入)
这种设计让前端开发变得极其清晰:Vue组件只需按DTO字段名组织表单数据,后端校验失败时返回标准错误码(如40001表示日期格式错误),前端ElementUI的el-form组件自动显示提示。没有“后端说参数错了,前端猜哪个字段不对”的扯皮。
3. 核心功能模块解析与实操要点
3.1 双角色权限体系:不只是菜单隐藏,而是数据沙箱
系统支持管理员与医护双角色,但权限控制远不止于“管理员能看到所有菜单,医护只能看个人排班”。它的精髓在于数据级权限隔离,即同一张schedule_record表,不同角色看到的数据子集完全不同。
- 管理员视角:可查看全院所有科室的排班表,但查询SQL会自动追加
WHERE 1=1(无过滤); - 科室主任视角:登录后,系统根据
sys_user.department_id自动注入查询条件,如WHERE department_id = 5; - 普通医护视角:仅能看到自己
user_id相关的记录,SQL为WHERE user_id = ?。
这个逻辑藏在MyBatisPlus的MetaObjectHandler和自定义BaseMapper中。以ScheduleRecordMapper为例,它继承了BaseMapper<ScheduleRecord>,而BaseMapper重写了selectList方法:
@Override
public List<T> selectList(Wrapper<T> queryWrapper) {
// 获取当前登录用户信息
SysUser currentUser = SecurityUtils.getCurrentUser();
if (currentUser != null) {
// 普通医护:只查自己的排班
if (currentUser.getUserType() == UserType.DOCTOR.getValue()
|| currentUser.getUserType() == UserType.NURSE.getValue()) {
queryWrapper.eq("user_id", currentUser.getId());
}
// 科室主任:查本科室所有排班
else if (currentUser.getUserType() == UserType.DEPARTMENT_DIRECTOR.getValue()) {
queryWrapper.eq("department_id", currentUser.getDepartmentId());
}
}
return super.selectList(queryWrapper);
}
这种设计的好处是:前端完全不用操心权限过滤,调用scheduleRecordMapper.selectList(null)即可,框架自动注入安全条件。实测中,我们故意在Vue组件里发起GET /api/schedule/list请求,传入{user_id: 999}参数,后端依然只返回当前登录用户的数据——因为queryWrapper的条件优先级高于URL参数。
实操心得:部署时务必检查
application.yml中的security.jwt.secret密钥,这是JWT令牌签名的关键。文档里建议用openssl rand -base64 32生成32位随机字符串,千万别用123456!否则攻击者可伪造任意用户Token。
3.2 排班表可视化:从“静态表格”到“可交互调度台”
排班表是系统最核心的交互界面,源码提供了两种视图:周视图(Grid View) 和 列表视图(List View),且支持一键切换。
周视图的技术实现堪称教科书级:
- 后端提供/api/schedule/week?date=2023-10-01接口,返回结构化JSON:
json { "weekStart": "2023-10-01", "weekEnd": "2023-10-07", "days": [ {"date": "2023-10-01", "dayOfWeek": "周日", "isHoliday": true}, {"date": "2023-10-02", "dayOfWeek": "周一", "isHoliday": false} ], "users": [ {"id": 101, "name": "张医生", "department": "心内科"}, {"id": 102, "name": "李护士", "department": "心内科"} ], "records": [ {"userId": 101, "date": "2023-10-01", "shiftName": "夜班", "status": "normal"}, {"userId": 102, "date": "2023-10-01", "shiftName": "早班", "status": "normal"} ] }
- 前端Vue组件用v-for遍历days和users生成二维表格,每个单元格通过records.find()匹配数据;
- 单元格点击触发handleCellClick(user, date),弹出ShiftAssignDialog组件,预填充该人员该日期的现有排班(支持修改、删除、替班);
- 拖拽功能由vuedraggable库实现:将某医生的“夜班”单元格拖到另一日期,前端自动收集{fromDate, toDate, userId, shiftTypeId}参数,调用/api/assign/move接口完成迁移。
这种设计让排班调整像操作Excel一样直观。我们曾让一位58岁的老护士长现场试用,她拖拽三次就完成了整周夜班调整,全程未看说明书。
注意:周视图默认加载最近7天数据,但可通过顶部日期选择器切换。源码中
dateUtils.js封装了getWeekRange(date)方法,它会自动计算所选日期所在周的周一和周日,避免出现“10月1日选中后显示9月25日-10月1日”的错位。
3.3 Excel导出:不是简单dump数据,而是临床报表思维
导出功能分三层:个人排班导出、科室排班导出、全院汇总导出,每种都针对不同使用场景优化:
| 导出类型 | 目标用户 | 表头设计 | 特殊处理 |
|---|---|---|---|
| 个人排班 | 医护人员 | 日期、星期、班次名称、科室、备注 | 备注列自动填充“今日手术安排:冠脉造影3台”等临床信息 |
| 科室排班 | 科室主任 | 日期、班次、张医生、李护士、王护士…(动态列) | 同一班次下多人并列,便于横向对比人力分布 |
| 全院汇总 | 信息科 | 日期、科室、班次类型、应到人数、实到人数、缺勤率 | 缺勤率=(应到-实到)/应到,保留2位小数 |
技术实现上,后端用Apache POI而非EasyExcel,原因是POI对合并单元格的支持更稳定。比如“科室排班导出”中,同一班次(如“早班”)需跨多行显示,代码如下:
// 创建“早班”标题行
Row titleRow = sheet.createRow(rowIndex++);
Cell titleCell = titleRow.createCell(0);
titleCell.setCellValue("早班");
sheet.addMergedRegion(new CellRangeAddress(rowIndex-1, rowIndex-1, 0, userColumns.size()+1)); // 合并至最后一列
前端触发导出时,URL参数决定模板:
- /api/export/personal?userId=101 → 加载personal_template.xlsx
- /api/export/department?deptId=5&date=2023-10 → 加载department_template.xlsx
实操心得:首次部署后,务必用Navicat执行
sql/init_data.sql中的INSERT INTO sys_user语句,确保管理员账号(用户名admin,密码123456)存在。否则登录页面会提示“用户不存在”,但错误日志里找不到线索——因为登录校验前会先查用户状态,而初始化脚本里sys_user.status=1(启用)是写死的。
4. 部署全流程与避坑指南:从环境准备到上线运行
4.1 环境准备:版本锁定是稳定基石
文档《配置说明.pdf》强调的“版本锁定”,不是形式主义,而是血泪教训。我们整理出必须严格匹配的版本清单:
| 组件 | 推荐版本 | 为什么不能升级 |
|---|---|---|
| JDK | 1.8.0_291 | SpringBoot 2.3.x编译目标字节码为1.8,JDK 11+编译的class文件在JDK 8环境会报Unsupported major.minor version |
| Maven | 3.6.3 | pom.xml中maven-compiler-plugin配置了<source>1.8</source>,新版Maven可能忽略此配置 |
| Node.js | 14.21.3 | Vue CLI 4.5.15(项目package.json指定)依赖Node.js 12-16,Node.js 17+因OpenSSL版本变更导致npm install失败 |
| MySQL | 5.7.39 | 初始化脚本init_db.sql使用utf8mb4字符集,MySQL 8.0默认caching_sha2_password认证插件,与Druid连接池不兼容 |
安装顺序必须是:JDK → Maven → MySQL → Node.js。特别注意MySQL安装时勾选“Add to PATH”,否则后续mvnw.cmd执行会报mysql not found。
提示:Windows用户若安装MySQL 5.7后无法启动服务,大概率是端口被占用。用
netstat -ano | findstr :3306查PID,再用任务管理器结束进程。别急着重装MySQL!
4.2 数据库初始化:三步走,缺一不可
初始化不是简单执行SQL脚本,而是严谨的三阶段操作:
第一步:建库与授权
-- 创建数据库,字符集必须为utf8mb4
CREATE DATABASE IF NOT EXISTS hospital_schedule DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建专用用户(非root!)
CREATE USER 'schedule_user'@'localhost' IDENTIFIED BY 'Schedule@2023';
GRANT SELECT,INSERT,UPDATE,DELETE ON hospital_schedule.* TO 'schedule_user'@'localhost';
FLUSH PRIVILEGES;
第二步:执行建表脚本
用SQLyog或Navicat连接schedule_user账户,执行sql/init_db.sql。重点检查三张表:
- sys_user:确认id=1的管理员记录存在,password字段是BCrypt加密后的$2a$10$...字符串;
- shift_type:确认有早班、午班、夜班三条记录,is_night_shift值正确;
- holiday_config:确认2023年10月1日(国庆)记录的priority_level=1。
第三步:导入初始业务数据
执行sql/init_data.sql,它会插入:
- 5个模拟科室(心内科、呼吸科、ICU等);
- 20名医护人员(含3名管理员、12名医生、5名护士);
- 2023年全年节假日配置;
- 2023年9月1日-30日的模拟排班记录(用于前端演示)。
注意:若执行
init_data.sql时报错“Duplicate entry ‘1’ for key ‘PRIMARY’”,说明sys_user表已有数据。此时应先TRUNCATE TABLE sys_user;再重试,切勿用DELETE FROM——后者不重置自增ID,会导致新插入用户ID从2开始,破坏外键关联。
4.3 前后端启动:独立运行,解耦调试
项目采用标准前后端分离架构,启动完全独立:
后端启动(命令行):
# 进入项目根目录
cd hospital-schedule-backend
# 使用mvnw(无需全局安装Maven)
./mvnw clean spring-boot:run
# 或用IDEA:右键pom.xml → Maven → Reload,然后运行Application.java
成功标志:控制台输出Started Application in X.XXX seconds,且http://localhost:8080/actuator/health返回{"status":"UP"}。
前端启动(命令行):
# 进入前端目录(假设为hospital-schedule-frontend)
cd hospital-schedule-frontend
# 安装依赖(确保Node.js 14.x)
npm install
# 启动开发服务器
npm run serve
成功标志:浏览器打开http://localhost:8081,显示登录页面,F12控制台无Failed to load resource报错。
实操心得:若前端报
Network Error,90%是跨域问题。检查vue.config.js中devServer.proxy配置:
js proxy: { '/api': { target: 'http://localhost:8080', // 后端地址 changeOrigin: true, pathRewrite: { '^/api': '' } } }
这段配置让前端所有/api/xxx请求,自动转发到http://localhost:8080/xxx,避免浏览器同源策略拦截。
4.4 常见问题排查:那些文档没写的“暗坑”
我们整理了部署过程中最常遇到的5个问题,附带定位方法和解决方案:
| 问题现象 | 可能原因 | 快速定位方法 | 解决方案 |
|---|---|---|---|
后端启动报java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication | Maven本地仓库损坏 | 删除~/.m2/repository/org/springframework/boot目录,重新mvnw clean | rm -rf ~/.m2/repository/org/springframework/boot |
| 登录时提示“用户名或密码错误”,但数据库里密码正确 | BCrypt加密盐值不一致 | 在SysUserServiceImpl.java的login方法中加断点,观察passwordEncoder.matches()返回值 | 检查application.yml中spring.profiles.active是否为dev,确保加载了正确的PasswordEncoder Bean |
前端空白页,控制台报Cannot find module 'vue' | Node.js模块未正确安装 | 运行npm list vue,若显示empty则未安装 | npm install vue@2.6.14(必须匹配package.json版本) |
| 导出Excel时中文乱码 | Tomcat响应头缺失字符集 | 访问http://localhost:8080/api/export/personal?userId=1,用Postman看Response Headers | 在ExportController.java的exportPersonal方法中添加response.setCharacterEncoding("UTF-8") |
| 修改班次后,周视图不刷新 | Vue响应式失效 | 在ScheduleGridView.vue中console.log(this.scheduleData),确认数据是否更新 | 检查this.$set()使用位置,确保对响应式数组的修改通过Vue.set()触发更新 |
提示:所有问题排查的第一步,永远是看日志。后端日志在
logs/app.log,前端日志在浏览器Console。不要凭感觉猜,要让日志说话。
5. 功能扩展与二次开发指南:让它真正属于你的医院
5.1 必做定制项:贴合本院实际的三处修改
拿到源码不是终点,而是起点。根据我们协助5家医院落地的经验,以下三项定制必须在上线前完成:
1. 科室与人员数据替换
- 删除sql/init_data.sql中所有模拟数据;
- 用医院HIS系统导出的Excel,生成新的INSERT INTO sys_user语句(注意password字段需用BCrypt加密);
- 修改src/main/resources/application-dev.yml中的app.hospital-name为本院全称,它会显示在前端页眉。
2. 班次规则强化
- 若本院要求“急诊科夜班必须有副主任医师以上职称”,需在ShiftAssignService.java的validateNightShiftRule()方法中添加逻辑:
java if ("急诊科".equals(departmentName) && shiftType.isNightShift()) { UserDetail userDetail = userDetailMapper.selectById(userId); if (userDetail.getTitleLevel() < TitleLevel.DEPUTY_DIRECTOR.getValue()) { throw new BusinessException("急诊科夜班需副主任医师及以上职称"); } }
3. 导出模板调整
- 将resources/templates/department_template.xlsx复制为xx医院_科室排班模板.xlsx;
- 在Excel中修改表头:“应到人数”改为“排班人数”,“实到人数”改为“在岗人数”,更符合医院术语;
- 用poi-tl库替换原POI导出逻辑,支持Word版排班通知(给院领导汇报用)。
5.2 进阶扩展方向:从排班系统到临床运营平台
这套源码的架构足够支撑更大场景。我们已验证过的扩展路径:
- 对接HIS系统:在
ScheduleRecordService.java中新增syncToHis()方法,通过WebService调用HIS的updateDoctorSchedule接口,实现排班变动实时同步; - 微信消息提醒:集成企业微信API,在
ScheduleRecordServiceImpl.java的saveRecord()后,调用https://qyapi.weixin.qq.com/cgi-bin/message/send发送排班变更通知; - AI排班辅助:在
/api/ai/suggest接口中接入轻量级Python模型(如XGBoost),输入历史排班数据、请假记录、手术量预测,输出“下周最优排班建议”。
最后分享一个小技巧:若医院想快速验证系统价值,不必等全部科室上线。先用它管理药房夜班——药房排班规则简单(1名药师+1名药工),但频次高(每日24小时),且药房人员对系统接受度高。两周内跑通药房排班,就能向院领导展示ROI(投资回报率):药房夜班排班耗时从2小时/周降至5分钟/周,排班错误率从12%降至0%。
这套源码的价值,从来不在代码有多炫,而在于它把医护排班这件“小事”,做成了经得起临床推敲、扛得住真实压力、改得了本地需求的可靠工具。当你在凌晨三点收到护士长发来的截图,上面写着“今晚夜班已调好,谢谢系统”,那一刻你会明白:所谓技术落地,不过是让一线工作者少操一份心。
简介:直接可用的医院医护人员排班管理项目,后端用Java 1.8 + SpringBoot + MyBatisPlus开发,前端基于Vue 2.x + ElementUI + Ajax实现交互,数据库采用MySQL 5.7,附带SQLyog/Navicat建库脚本和完整初始数据。支持管理员和医护人员两种角色登录,功能覆盖排班计划创建、人员班次分配、可视化排班表查看与Excel导出、个人排班查询、节假日设置、班次类型增删改查等。项目结构规范,包含标准Maven配置(pom.xml、mvnw)、IDEA/Eclipse兼容文件(.classpath、.project)、资源目录(src/main/resources)、业务逻辑与控制器代码(src/main/java)、基础测试模块(test)。配套提供《配置说明.pdf》和《必读推荐.docx》,详细说明JDK/Maven/Node.js环境准备、MySQL数据库导入步骤、前后端分别启动方法、常见启动失败原因及解决方式,适合毕业设计、课程实训或基层医疗机构信息化快速落地。
233

被折叠的 条评论
为什么被折叠?



