课程排课系统从零开发实战:基于Spring Boot + Vue的智能排课方案
课程排课是教务管理中耗时、容易出错的环节。本文将从技术选型、数据库设计、核心算法三个维度,分享一套可落地的课程排课系统开发方案。方案基于SpringBoot+MyBatisPlus+MySQL搭建后端服务,用户端采用UniApp适配多端,管理后台使用Vue+ElementUI构建,支持智能排课、调课冲突检测、教师课时统计等核心功能。如果你正在规划课程排课系统的技术架构,本文提供的表结构设计与贪心算法实现可以直接复用。
一、课程排课系统技术选型与整体架构
在课程排课系统的技术选型上,参考成熟预约类系统的经验,推荐采用前后端分离架构。
后端服务基于 Spring Boot 2.x + MyBatis Plus + MySQL 8.x 构建。Spring Boot 提供自动配置与生态整合能力,MyBatis Plus 简化单表 CRUD 操作,MySQL 负责存储课程、教师、教室、排课结果等结构化数据。对于需要高并发的选课场景,可引入 Redis 缓存热门课程时段,但基础版本的课程排课系统无需过度设计。
用户端采用 UniApp 框架,基于 Vue 语法开发,一套代码可同时编译为小程序、H5、公众号网页及 Android/iOS App。管理后台使用 Vue + ElementUI,表格展示排课列表、表单处理调课申请、日历组件可视化展示教室占用情况。整个系统可拆分为以下模块:
- 基础数据管理:教师信息、教室资源、课程信息、班级信息
- 排课核心引擎:自动排课算法、冲突检测、人工调课
- 课表展示:周课表视图、教师课表、教室课表
- 消息通知:排课结果推送、调课提醒(可集成短信或模板消息)
二、课程排课数据库设计:六张核心表的结构与关系
排课系统的数据模型是核心。建议设计以下六张表,以支持灵活的排课与调课操作。
1. 教师表(teacher)
字段包括:id、name、teacher_no(教师工号)、title(职称)、max_hours_per_week(周课时数,用于排课约束)、available_days(可授课星期,JSON数组存储,例如[1,2,3,4,5]表示周一至周五)。
2. 教室表(classroom)
核心字段:id、room_no(教室编号)、capacity(容量)、room_type(教室类型,如普通教室/机房/多媒体)、equipment(设备信息,如投影/白板)。排课系统需要根据课程类型匹配教室设备,比如编程课需要机房,普通理论课匹配多媒体教室即可。
3. 课程表(course)
字段:id、course_name、course_code、credit(学分)、total_hours(总学时)、course_type(必修/选修)、requires_room_type(所需教室类型)、requires_equipment(所需设备)。
4. 班级表(class)
字段:id、class_name、grade(年级)、student_count(学生人数)、available_days(班级可上课时间,JSON数组)。班级时间约束通常由学校统一规划,比如周一上午不排课。
5. 排课结果表(schedule)
这是核心结果表,字段包括:id、course_id、teacher_id、classroom_id、class_id、weekday(星期几,1-7)、start_section(开始节次)、end_section(结束节次)、week_list(上课周次,如"1-16周")、semester(学期)。
6. 调课记录表(schedule_change_log)
用于追踪调课历史:id、old_schedule_id、new_schedule_id、change_reason(调课原因)、operator_id(操作人)、create_time。保留调课日志可帮助追溯课表变更过程,避免责任不清。
各表关系明确:schedule 表通过外键关联 teacher、classroom、course、class 四张基础表。课程排课查询时,只需关联这四张表即可生成完整课表。
三、课程排课核心算法:贪心策略 + 冲突检测的实现
自动排课是系统的核心难点。常用的算法有遗传算法、模拟退火算法,但对于大多数职业院校和培训机构,贪心策略已经足够。贪心的思路是:优先为约束多的课程排课,每次选择早可用时间段。
以下是简化版的排课算法流程:
- 计算所有课程的优先级分数。分数 = 课程总学时 + 教室特殊要求权重 + 教师授课天数限制权重。
- 按优先级分数从高到低对课程排序。
- 遍历排序后的课程,为每个课程查找可用时间段:
- 查询教师在该时间段是否空闲(排除教师不可用星期、排除已排课程)。
- 查询班级在该时间段是否空闲。
- 查询教室在该时间段是否空闲,且满足教室类型与设备要求。
- 若找不到可用时间段,则将课程标记为“待人工处理”,继续下一门课程。
冲突检测可用 SQL 实现,查询语句如下:
-- 检测某教师在某时间段是否已被排课SELECTCOUNT(*)FROMscheduleWHEREteacher_id=#{teacherId}ANDweekday=#{weekday}ANDweek_list=#{weekList}ANDNOT(end_section<#{startSection} OR start_section > #{endSection})这条 SQL 的原理是判断时间区间是否重叠:两段时间不重叠的条件是“一段的结束时间早于另一段的开始时间”或“一段的开始时间晚于另一段的结束时间”。
调课场景同样复用该冲突检测逻辑。当管理员发起调课申请时,先校验新时间段是否冲突,若无冲突则直接更新 schedule 表,并在 schedule_change_log 中写入调课原因。
四、课程排课系统实战经验:多端适配与性能优化
1. 用户端课表渲染的跨端兼容
用户端采用 UniApp 开发。课表页面通常用表格形式展示,但小程序端 Canvas 绘制复杂表格性能较差。推荐使用 flex 布局 + 百分比宽度实现周课表,星期作为行,节次作为列。每个课程格子用定位的 view 组件渲染,背景色根据课程类型动态计算。需要注意 App 端与小程序端对 CSS 的支持差异,避免使用 CSS Grid,统一使用 Flex 布局。
2. 后端查询优化
排课结果查询是高频操作,特别是开学初全体师生同时查看课表。建议在 schedule 表建立联合索引(teacher_id, weekday, week_list)、(class_id, weekday)、(classroom_id, weekday, start_section)。如果单表数据超过百万级,可以按学期分表,例如schedule_2025_spring。
3. 排课结果导出
管理后台需要将排课结果导出为 Excel。使用 EasyExcel 库,将 schedule 表数据关联查询后,按教师维度分组生成多个 sheet,每个 sheet 包含该教师一周的课程安排。导出时注意设置单元格合并,相同节次合并为一个单元格,提升报表可读性。
4. 周次处理
真实场景中,单周和双周课程安排不同(如单周周一上午上数学课)。数据库设计时,week_list 字段可使用字符串“1,3,5,7,9,11,13,15”表示单周。查询时应使用 FIND_IN_SET 函数或拆分成数组后判断。前端展示时,根据当前周次过滤显示对应课程。
五、课程排课面临的常见问题与FAQ
Q1:课程排课系统如何处理教师临时调课需求?
调课功能需要管理后台提供“交换”和“平移”两种模式。交换是指两个教师的课程互换时间,平移是指将某一课程直接调整到空闲时间段。每次调课操作前,系统自动调用冲突检测接口,校验新时间段的教室、教师、班级三重冲突。调课成功后,通过消息推送通知相关学生和教师,并记录变更日志便于追溯。
Q2:排课算法无法排完所有课程怎么办?
贪心算法天然存在局部问题。当有课程无法安排时,系统应将未排课课程自动列入“待人工处理”列表。此时可提供“手动拖拽排课”界面,以周课表的形式展示空闲资源,由教务人员拖动课程到目标时段,拖动时同样实时校验冲突。这种“自动预排 + 人工微调”的组合模式,在实际项目中的终排课完成率普遍接近100%。
Q3:课程排课系统的数据库如何选择?
中小规模学校(100个班级以内)使用 MySQL 完全足够。MySQL 8.x 的窗口函数和 JSON 类型可以方便处理排课统计和复杂查询。如果目标是大型高校(超过1000个班级、数万条排课数据),则需要考虑使用 PostgreSQL 或分布式数据库,但架构复杂度会显著提升,不建议作为初版方案。
Q4:课程排课系统能直接复用预约类系统的源码吗?
预约系统的核心是“资源 + 时间段 + 用户”的三元组模型,课程排课系统也是“教师/教室 + 节次 + 班级”的匹配逻辑,两者模型相似。参考预约系统的 Spring Boot + MyBatis Plus + UniApp + Vue 技术栈是可行的。但排课系统额外需要周次判断、单双周、多学期管理等业务能力,这些需要二次开发。建议复用基础的用户权限、教室管理、消息推送模块,排课引擎部分独立开发。
Q5:排课结果发布后,发现班级人数超出教室容量如何处理?
这属于基础数据未校验导致的异常。开发阶段应在课程与教室绑定环节设置硬性校验:当班级学生数大于所选教室容量时,前端提交时拦截并提示。若已发布的课表出现该问题,需要提供“批量换教室”功能,管理员选择目标教室后,系统自动筛选所有不匹配的排课记录,并推荐同时间空闲且容量足够的教室,一键完成更换并通知相关班级。