首页 / 资讯中心 / 文章详情

用AI编程工具Trae快速搭建教师代课系统

用AI编程工具Trae快速搭建教师代课系统 ★ FEATURED ARTICLE
最近我把一个拖了挺久的活儿用 AI 编程工具 Trae 给收尾了——给学校教务那边做了一个教师代课系统。说出来你可能不信从需求梳理到系统能跑起来只花了一个周末而且大部分代码是 AI 生成的。这个系统解决的痛点很具体老师临时请假、出差、培训课没人上教务主任靠手动安排代课累不说还容易漏课、排重课。我做的这套东西老师线上申请请假教务审批通过后系统自动生成代课安排还带冲突检测、消息通知、课时统计。适合谁呢教务管理人员可以拿去用学校信息中心的老师可以拿来改改部署想学 AI 辅助开发的朋友也能从里面看到怎么用自然语言驱动一个完整项目落地源码我放了可修改版本后面会说。1. 项目缘起与需求拆解1.1 代课系统的真实痛点以前学校里的代课安排基本靠两条路一是微信群里喊“明天我第三节有事谁能帮我上一下”然后教务主任开始手动在课表上找空档二是用 Excel 表格记录哪个老师请了假、哪节课换给了谁全靠手工填。这种做法的毛病我见得多了同一节课被两个人重复认领、代课老师跟原课程时间冲突、月底统计课时费时翻遍聊天记录也找不齐数据。更麻烦的是代课不是简单的“找个人顶上”。学科得差不多吧年级最好别跨太远吧还得保证代课老师自己那个时间段没课。把这些条件叠在一块儿人工匹配的效率极低碰上多个老师同时请假的日子教务主任一上午就耗在这上面了。我接这活儿的时候对方只提了一个要求能把“自动匹配代课老师”这件事做了就谢天谢地。所以我一口气把请假申请、审批、匹配、通知、统计全打通了。1.2 核心功能清单与边界先对着真实场景过了一遍最终确定系统只做四件核心的事请假管理老师提交请假申请选择请假起止时间、对应课程、请假事由教务审批。代课匹配审批通过后系统自动从“当前空闲且学科匹配”的教师里挑出最合适的人生成代课安排。通知与统计被选中的代课老师能在站内看到消息教务也能导出代课课时统计表。基础数据维护教师列表、课程表按周导入不搞复杂的排课功能。边界我也划得很清楚不碰课表编排不做全年总课表规划因为学校原有排课系统已经够用我只需要拿到“谁在哪个时间段有课”这个静态数据用来判断冲突就够了。这个取舍很重要——如果试图把排课和代课揉在一起项目复杂度会翻倍AI 再强也容易失控。2. 技术选型与整体设计2.1 为什么选 Trae 做辅助开发说实话这类管理系统我自己手写也能写但效率完全不在一个量级。Trae 给我的最大帮助不是简单的“代码自动补全”而是“我问一句它给我生成一整块可运行代码”。比如我直接说“写一个请假审批接口状态从 PENDING 改为 APPROVED 时校验当前用户是否有教务权限”它就能把 FastAPI 的依赖注入、权限检查、数据库更新全套给我写出来我只需要对着业务场景改几行。我总结了几条经验越具体的问题Trae 给出的代码越准。比如“用 Pydantic 定义请求体”就比“帮我写个接口”有效得多。另外让 AI 分步生成每轮只聚焦一个模块比一次让它把整个系统生成完质量高得多。我基本是“骨架一次性生成血肉分步填充”。2.2 技术栈与架构设计选型时要考虑一个新手上手成本。我的方案是后端Python FastAPI够轻量自带 Swagger 文档方便调试。前端Vue 3 Element PlusUI 组件现成表格、表单、弹窗这些后台常用组件都有。数据库SQLite单个文件搞定一切不用装数据库服务适合中小学校的使用规模。部署Docker 打包里面跑一个后端容器和一个前端静态文件服务扔到校内服务器就能用。为什么这么选因为我需要让这个系统“拿过去就能跑”而不是让教务老师先折腾 MySQL。SQLite 对这个数据量几百个教师、几千条代课记录完全够用。后端用 FastAPI 则是因为它配合 Pydantic 做参数校验非常顺手生成的 OpenAPI 文档能直接给前端看接口结构。前端选 Vue 3 加 Element Plus纯粹是组件省心——写后台管理页面最大的工作量往往在表格和表单有现成的组件能少写三分之一代码。整体数据流其实很直观教师在前端提交请假申请后端写入 SQLite教务在另一页面审批审批通过后触发匹配服务匹配结果写入代课记录表代课老师登录后看到待认领的站内通知月底管理员导出统计 Excel。3. 用 Trae 从零到一实现系统3.1 第一步让 AI 生成项目骨架我先在一个空目录里让 Trae 创建了后端基础结构。当时的 prompt 大概是这样的用 FastAPI 写一个教师代课系统后端包含教师、请假单、课程表、代课记录四张表提供以下功能新增教师、按周导入课程表、提交请假申请、审批请假、自动匹配代课老师。数据库用 SQLiteORM 用 SQLAlchemy。先给出项目目录结构和 models 定义。Trae 立刻给我拉出了一个目录app/ ├── main.py # 应用入口 ├── models.py # SQLAlchemy 模型 ├── schemas.py # Pydantic 请求/响应模型 ├── crud.py # 数据库操作函数 ├── api/ │ ├── teachers.py # 教师相关路由 │ ├── leaves.py # 请假相关路由 │ ├── schedules.py # 课程表相关路由 │ └── substitutions.py # 代课相关路由 └── services/ └── matcher.py # 代课匹配算法这一步的价值在于项目结构一旦合理后面所有功能都是往对应的文件里“填肉”。我让 Trae 明确用了两层路由——一层面向 REST API一层放核心匹配逻辑这样后面改算法时不会把 API 写乱。3.2 核心模块请假申请与审批流程实现请假申请接口是第一个重点。我要求 Trae 实现“教师提交请假、教务审批、状态不可逆向跳转”的逻辑。生成的代码核心部分长这样# app/api/leaves.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app import models, schemas router APIRouter(prefix/leaves, tags[leaves]) router.post(/, response_modelschemas.LeaveOut) def create_leave(leave_in: schemas.LeaveCreate, db: Session Depends(get_db)): # 检查请假时间是否与该教师的已有课程冲突 conflict check_teacher_conflict( db, teacher_idleave_in.teacher_id, start_periodleave_in.start_period, end_periodleave_in.end_period, dateleave_in.date ) if conflict: raise HTTPException(status_code400, detail该时间段已有课程冲突) leave models.Leave(**leave_in.dict(), statusPENDING) db.add(leave) db.commit() db.refresh(leave) return leave router.post(/{leave_id}/approve, response_modelschemas.LeaveOut) def approve_leave(leave_id: int, db: Session Depends(get_db)): leave db.query(models.Leave).filter(models.Leave.id leave_id).first() if not leave: raise HTTPException(status_code404, detail请假单不存在) if leave.status ! PENDING: raise HTTPException(status_code400, detail只能审批待处理状态) leave.status APPROVED db.commit() db.refresh(leave) # 审批通过后触发代课匹配 generate_substitution(db, leave_id) return leave这里我特意让 AI 保留了“从 PENDING 到 APPROVED”的状态校验不能直接从申请跳成其他状态。审批动作放在单独的接口里这样后续要做“审批记录”“操作日志”改这一个接口就行。3.3 代课匹配算法的设计与实现匹配算法是整个系统的灵魂也是我人工修改最多的部分。Trae 第一版生成的算法很简单遍历所有教师找出同时刻没课且学科相同的人按工号顺序取第一个。这显然不够合理。我改成按“胜任度”加权排序规则一共有三条学科相同得 3 分学科相近比如数学代物理得 1 分。该老师当天已有代课数越少越优先。尽量同一年级跨年级扣 1 分。代码实现是这样的# app/services/matcher.py from sqlalchemy.orm import Session def calculate_teacher_score(teacher, leave, db): score 0 # 1. 学科匹配 if teacher.subject leave.subject: score 3 elif len({teacher.subject, leave.subject}) 1: # 简单判断是否为相近学科实际可以维护一个学科映射表 score 1 # 2. 当年代课次数越少越优先 current_sub_count db.query(models.Substitution).filter( models.Substitution.sub_teacher_id teacher.id, models.Substitution.status ASSIGNED ).count() score - 0.5 * current_sub_count # 3. 同年级加分跨年级减分 if teacher.grade leave.grade: score 2 else: score - 1 return score def find_best_substituter(db, leave_id): leave db.query(models.Leave).filter(models.Leave.id leave_id).first() # 查询在请假时间点空闲的教师 busy_ids get_busy_teacher_ids(db, leave.date, leave.start_period, leave.end_period) candidates db.query(models.Teacher).filter( models.Teacher.id.notin_(busy_ids), models.Teacher.id ! leave.teacher_id ).all() if not candidates: return None best max(candidates, keylambda t: calculate_teacher_score(t, leave, db)) return best匹配成功后生成一条代课记录把代课老师的 ID、原教师 ID、课程时间段、状态都存进去。紧接着给代课老师发站内通知。3.4 界面与交互细节打磨前端部分我几乎都是让 Trae 生成 Element Plus 的表格组件。一个典型的列表页 prompt用 Vue3 Element Plus 写一个请假申请列表页面展示教师姓名、请假日期、节次、状态、申请时间状态用 el-tag 显示不同颜色。保留“审批通过”和“驳回”按钮点击后调用后端接口。生成出来确实能跑但样式很“素”。我又让它改了间距、加了 loading 状态还补了“代课老师”列——因为审批通过后这一列要立刻显示匹配结果。交互上最重要的细节是审批后要禁用重复点击的按钮避免同一请假单被重复审批。这个小问题在实际使用中特别常见我专门在前端加了loading和状态判断。4. 关键代码解读与踩坑记录4.1 请假状态机设计这套系统的状态流转应该是像下面这张表每一步都不能跳当前状态可流转到触发条件PENDINGAPPROVED教务审批通过PENDINGREJECTED教务审批驳回APPROVEDCOMPLETED代课记录全部完成后自动置为完成APPROVEDCANCELLED原教师销假且代课尚未开始这里我在代码里定义了一个状态集合任何状态转换都用同一个函数校验ALLOWED_TRANSITIONS { PENDING: {APPROVED, REJECTED}, APPROVED: {COMPLETED, CANCELLED}, } def transition_leave(db, leave, new_status): if new_status not in ALLOWED_TRANSITIONS.get(leave.status, set()): raise HTTPException(status_code400, detailf状态不能从 {leave.status} 变为 {new_status}) leave.status new_status db.commit()踩坑点如果用户直接改数据库状态这个状态机的校验就失效了。所以我后来把“销假”也做成了接口不允许手动改库。4.2 冲突检测与时间重叠判断代课匹配里最容易出错的是时间段重叠判断。刚开始我写的判断是很蠢的相等比较后来才改成区间重叠。判断两个时间段是否冲突标准条件是一段开始时间早于另一段结束时间、且结束时间晚于另一段开始时间def has_conflict(new_start, new_end, exist_start, exist_end): return new_start exist_end and new_end exist_start一对比如 14:00-15:00 和 14:30-15:30就冲突。但如果数据库存的是“节次”而非具体时间就最好用“星期几 第几节”来对齐。我这里就踩了坑课表里有的是“第1、2节”这种写法有的又是“8:00-9:40”统一换算成 1~12 的数字节次字段后才顺利比较。4.3 代课消息通知简单邮件/站内信代课系统对时效性要求高我不可能真去接短信网关所以做了站内信。实现也很简单就是往notifications表插一条记录字段包含接收人、内容、是否已读。def send_station_message(db, user_id, title, content): note models.Notification( receiver_iduser_id, titletitle, contentcontent, readFalse, created_atnow() ) db.add(note) db.commit()同时教务和代课老师登录后页面上会出现一个红点提醒读取未读通知的接口会同时把已读状态标记掉。虽然简陋但解决了实际问题。如果学校内部已有企业微信或钉钉可以在这里扩展成 webhook 推送我在代码里预留了notify_url字段。4.4 数据导出与统计报表月底算代课课时费是教务最头疼的事我做了个导出功能直接生成 Excel 文件。用 openpyxl 写表格按代课教师汇总总课时数from openpyxl import Workbook def export_substitution_report(db, month): wb Workbook() ws wb.active ws.append([教师, 累计代课节数, 涉及学科]) results db.query( models.Substitution.sub_teacher_id, func.count().label(cnt) ).filter( models.Substitution.created_at.like(f{month}%) ).group_by(models.Substitution.sub_teacher_id).all() for row in results: ws.append(row) # 返回 BytesIO 由接口流写入 output BytesIO() wb.save(output) return output.getvalue()导出接口注意加权限校验不能任意登录的人都导出全部数据。我是给这个接口挂了admin_required依赖。5. 常见问题与排查实录5.1 问题速查表项目完成后我整理了一张问题表希望帮你少走弯路现象原因解决方式前端请求后端一直报跨域FastAPI 没配置 CORSMiddleware加上allow_origins[*]内网使用勉强可以请假审批通过后代课老师字段为空匹配服务没有被调用检查generate_substitution是否在 approve 接口内被调用SQLite 报 database is locked多线程同时写数据库打开连接时设置check_same_threadFalse 使用连接池上限代课时间重复但不报错课程表里存储的是字符串“1-2节”未转为整数比较新增period_start/period_end整型字段页面表格数据量超过 1000 条后就慢前端全量渲染改成了分页组件同时后端limit和offset配合5.2 独家避坑技巧我这次项目里最值得说的避坑经验有三点。第一AI 生成的代码权限校验一定要自己加强。Trae 默认不会自动给你的接口加登录验证我让它写了几次它总是忘掉有没有current_user参数。结果就是任何人都能调审批接口。我后来给所有写操作都手动加了一个get_current_admin的依赖再让 Trae 生成新的接口模板时直接告诉它“继承 admin 依赖”。第二一定要及时做 git 备份。用 AI 编程的好处是改得快坏处是它某一次生成“改进版”的时候可能把原本对的逻辑改坏。我中途出现过匹配结果突然全部变成None的情况一查是 AI 修改时把db.query后面的 filter 条件给丢了。没有 git 回滚的话我可能得重新让 AI 生成一遍效率会大打折扣。第三测试数据要尽量贴近真实。我一开始用了假名字和随机时间系统跑通后觉得挺稳结果一导入真实课表发现跨年级代课评分有问题。因为真实数据里有初中部和高中部的教师学科代码不一致。所以从第一天就应该导入真实课表的脱敏版本哪怕数据量小也能让 AI 生成逻辑时考虑到边界情况。整个系统开发下来我最大的感受是AI 不是替你写代码而是替你扫平了那些“已知的重复劳动”。真正值钱的部分比如业务规则、状态机、冲突判断还是要靠人去梳理、去盯。Trae 帮我把浪费时间的地方全压缩了我才有精力去死磕匹配权重和用户体验。源码我是从一个可运行的版本里拆出来的把学校和教师姓名全替换成了模拟数据数据库文件也重新初始化过了。如果你需要部署脚本和完整源码可以直接找我拿我会附上 README里面写了怎么用 Docker 一键启动以及一套假数据方便你打开就能看到页面长什么样。
阅读完成 · 觉得有帮助?
咨询建站