Files
gongxue-base/docs/superpowers/plans/2026-07-13-binary-course-attendance.md

4.3 KiB
Raw Blame History

课程二态考勤与截止自动结算 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 教师课程考勤只显示已打卡/未打卡,并在课程截止后自动最终拉取、落库和完成场次。

Architecture: 保留钉钉原始迟到状态;课程服务根据“是否存在实际打卡时间”生成临时二态结果和最终 present/absent。新增 Attendance 模块内的 NestJS 定时结算服务,每分钟扫描到期课程并复用导入与课程考勤服务,失败留待下一轮补偿。

Tech Stack: NestJS 11、@nestjs/schedule 6、TypeORM 0.3、Jest、React 19、Ant Design 6。

Global Constraints

  • 仅调整排课关联的课程考勤。
  • 不迁移历史记录,不改变钉钉原始记录。
  • 不新增依赖、队列、兼容层或重复状态模型。
  • 课程截止后有实际打卡写 present,无实际打卡写 absent
  • 单节失败不得阻断其他课程,后续扫描必须可补偿。

Task 1: 课程二态映射

Files:

  • Modify: apps/server/src/attendance/attendance.service.ts
  • Test: apps/server/src/attendance/attendance.lesson-session.spec.ts

Interfaces:

  • Produces: createLessonAttendanceFromDingTalk(scheduleId, lessonDate, userId, finalize?)finalize=false 返回临时二态,finalize=true 写最终二态并完成场次。

  • 添加失败测试:Late 且有 checkInTime 应为 present;无实际时间应为 pending;最终结算时无时间应为 absent 且 session 为 completed

  • 运行 npm test -- attendance.lesson-session.spec.ts --runInBand,确认新增断言按预期失败。

  • 将课程状态映射改为只检查课程窗口内是否存在 checkInTimecheckOutTime;最终结算参数控制无打卡为 absent,并在同一事务完成场次。

  • 再次运行相同测试,确认通过。

Task 2: 截止自动结算

Files:

  • Create: apps/server/src/attendance/attendance-settlement.service.ts
  • Create: apps/server/src/attendance/attendance-settlement.service.spec.ts
  • Modify: apps/server/src/attendance/attendance.module.ts
  • Modify: apps/server/src/app.module.ts

Interfaces:

  • Consumes: AttendanceImportService.importFromDingTalk(...)AttendanceService.getTeacherClassDingUserIds(...)AttendanceService.createLessonAttendanceFromDingTalk(..., true)

  • Produces: AttendanceSettlementService.settleEndedLessons(now?: Date): Promise<void>,由 @Cron('* * * * *') 调用。

  • 添加失败测试:未截止不处理、已完成不处理、到期课程最终拉取并结算、一个课程失败后继续处理下一个、昨日跨午夜课程可结算。

  • 运行 npm test -- attendance-settlement.service.spec.ts --runInBand,确认因服务不存在而失败。

  • 实现每分钟扫描今天普通到期课程及昨日跨午夜到期课程;逐课程捕获异常并记录;使用课程 teacherId 作为自动导入审计用户。

  • AttendanceModule 注册服务,在根模块启用 ScheduleModule.forRoot()

  • 再次运行相同测试,确认通过。

Task 3: 教师二态界面

Files:

  • Modify: apps/admin/src/pages/Attendance/attendance-workspace.ts
  • Modify: apps/admin/src/pages/Attendance/index.tsx
  • Test: apps/admin/src/pages/Attendance/attendance-workspace.test.ts

Interfaces:

  • Produces: summarizeLessonCheckins(records),将 present/late 归为已打卡,将其余归为未打卡。

  • 添加失败测试:present 与遗留 late 均计入已打卡,pending/absent 计入未打卡。

  • 运行 admin 的定向测试命令并确认失败。

  • 教师抽屉改为“已打卡 / 未打卡”标签、汇总和手动修改选项;管理员档案保持原五态。

  • 再次运行定向测试,确认通过。

Task 4: 聚焦验证

Files:

  • Verify only; no planned production edits.

  • 运行 server 两个定向 Jest 测试文件。

  • 运行 server npm run typecheck

  • 运行 admin 定向测试与 npm run typecheck

  • 用现有数据库场景确认王子琪的 Late 在教师视图归为已打卡、陈浩无记录归为未打卡;不修改数据库数据。