Files
aca-syllabu-service/课程表改造计划.md
2026-10-14 16:15:16 +08:00

135 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AcaSyllabu 课程表改造计划
> 创建日期:2026-10-11
> **执行状态(2026-10-11):全部完成。**
> - 后端:包名已改 `com.yunhai.acasyllabu`,宿舍通知业务已删(保留日志/附件/基建),新增 Timetable/TimetableSlot 实体 + TimetableController(Get/Save/SavePhoto/RemovePhoto/Subjects)+ ClassService 学科接口;`mvn clean compile` BUILD SUCCESS;本地启动冒烟通过(/actuator/health 200,未登录访问 /api/* 正确 302 跳 SSO)。
> - 前端:新增 `views/syllabus/TimetableEdit.vue`(参考页整体移植)+ `api/module/syllabus.ts` + `types/syllabus.ts`,路由/菜单/标题全部切换为课程表,dorm 业务已删;`npm run build` 通过。
> - 待联调:账号 lijing/a123123 为 CAS 平台账号,需平台与班级服务在线后做登录态全流程验证(见任务 7)。
> 后端项目:`E:\YHXT\java\AcaSyllabu`(原包 `com.yunhai.dormnotice`,宿舍通知/家校活动遗留)
> 前端项目:`E:\YHXT\view\AcaSyllabu`(Vue3 + alova + view-ui-plus,原为宿舍通知页面)
> 参考项目:`E:\YHXT\java\UserclassService`(UserContext / SysOperationLogAspect / 学科 oapi 出处)
> 参考 UI:`E:\YHXT\view\AcaSyllabu\timetable-site\index.html`(qoder 站点本地副本,本次改造的界面蓝本)
> 目标:改造为**课程表服务**——包名 `com.yunhai.acasyllabu`,电子课程表(节次×星期编排)+ 照片课程表(图片上传),前后端真实联调。
---
## 一、业务需求
课程表分两种形式,均以「班级」为维度维护:
1. **电子课程表**(参考 timetable-site/index.html):
- 顶部选择班级;「电子版 / 照片版」两个页签。
- 编辑表格:`节次 | 星期一~星期日 | 开始时间 | 结束时间 | 操作(删除)`。
- 节次默认 10 节(可新增/删除/恢复默认);每个单元格下拉选择学科。
- 按开始时间自动判定时段:**上午 < 12:30;下午 12:30–18:30;晚自习 ≥ 18:30**,分组行展示。
- 支持预览课表(时段分栏课表 + 打印)。
2. **照片课程表**:按班级上传一张课表照片(预览/替换/移除)。
## 二、现状调研摘要
### 2.1 后端(com.yunhai.dormnotice)
- Spring Boot 2.7.18 + Java 8 + JPA/Hibernate + MySQL;端口 8105;本地库已是 `aca_syllabu`;生产 context-path `/dormnotice`、库 `bsch_dormnotice`(未改)。
- 上一轮重构已移植:`UserContext`、`ControllerUserContextAspect`、`SysOperationLogAspect`(异步落库)、`SysOperationLog`、`UpFile` 附件体系、`ClassService`(班级树/学生树,5 分钟缓存,直连 `{yh.open.bschclass}/oapi`)。
- **无学科接口**——ClassService 只有教师/学生树,需补 `getSchSubjectList`。
- 宿舍通知业务待删:Activity/ActivityRead/ActivitySignup/ContactGroup/ContactGroupUser 实体 + Contacts/Dict 控制器 + model/activity 15 个 VO。
- 已知隐患:`BaseApiController` import 了 `model.activity.ClassTreeNodeVo`(与 bsch 包同名类重复),删 activity 包前必须改为 `model.bsch.ClassTreeNodeVo`;两个切面的切点/排除名单硬编码 `com.yunhai.dormnotice`。
### 2.2 前端(view/AcaSyllabu)
- dev 端口 8078,代理 `/api → http://localhost:8105`(与后端一致,无需改)。
- 路由静态注册(routes.ts + meta.modId),菜单由后端 `GetUserMod` 下发经 menuRoute.ts 映射;dorm 7 页面 + `api/module/dorm.ts` + `types/dorm.ts` 为待删业务。
- alova 封装(get/postJSON/postForm)+ `{code,msg,data}` 解包 + 302 跳 SSO 均为可复用基建。
- `GradeClassSel`/`BschSubjectSelect`/`UploadImg` 是其它项目拷来的死组件(依赖的 store 字段不存在),不可直接用。
- `timetable-site/index.html`:完整交互蓝本(时段色板、学科色板、预览 sheet、照片 dropzone、打印样式俱全),整体迁入 Vue 页面。
### 2.3 构建环境
- 后端:`D:\Program Files\Java\jdk-1.8` + `D:\Program Files\Java\maven\apache-maven-3.6.1`(需 `JAVA_HOME`);平台依赖已在本地 `~/.m2` 缓存。
- 前端:Node 24 + npm,`node_modules` 缺失需先 `npm install`。
## 三、数据库设计(ddl-auto=update 自动建表,SQL 脚本同步留存)
| 表 | 字段 | 说明 |
|---|---|---|
| `timetable` | id、sch_id、class_id、class_name、grade_name、teacher_id、photo_file_id、create/update 审计 | 每班一条,`(sch_id, class_id)` 唯一;**teacher_id 为平台用户/教师 id,不存账号**;photo_file_id 关联 up_file |
| `timetable_slot` | id、timetable_id、sort_order、start_time、end_time、day_1..day_7 | 每节次一行;start/end 存 `HH:mm`;day_N 存学科名(空=未排) |
| `sys_operation_log` | (沿用) | 操作日志,切面异步落库 |
| `up_file` | (沿用) | 附件表,topic_type=`timetable` |
派生数据(时段分组、统计)不落库,前后端按开始时间实时计算。
> **2026-10-12 变更**:时段判断已移除。所属时段改为显式维护在模板行上(`timetable_template_row.band` = es/am/noon/pm/ev),
> 保存后不随开始时间变化;节次与空白行都落在时段里,启用哪些时段就要维护哪些时段的行——每个启用时段至少保留一行(节次或空白行),
> 只剩一行时该行不允许删除、也不允许移出该时段;课表编排页按生效模板行的 band 分组展示。上文「按开始时间自动判定时段」为改造初期的原始设计,仅作历史记录。
## 四、任务分解
### 任务 1:后端框架改名 `com.yunhai.dormnotice` → `com.yunhai.acasyllabu`
| # | 改动点 |
|---|---|
| 1.1 | 源码目录 `java/com/yunhai/dormnotice/` → `acasyllabu/`,全部 package/import 替换(含两切面切点表达式与 LogController 排除名单) |
| 1.2 | 主类 `DormNoticeApplication` → `AcaSyllabuApplication`(scanBasePackages 同步) |
| 1.3 | pom.xml:artifactId/name/finalName/mainClass → acasyllabu;ci profile 输出目录同步 |
| 1.4 | bootstrap.yml:`spring.application.name: acasyllabu`,Nacos dataId `acasyllabu.yaml` |
| 1.5 | application.yml:sms.module-id 改名;docker/application-prod.yml:context-path `/acasyllabu`、库 `bsch_acasyllabu`;Dockerfile EXPOSE 对齐 |
| 1.6 | logback-spring.xml / SwaggerConfig 标题 / notice.iml 及 .idea 辅助文件同步 |
### 任务 2:删除宿舍通知业务,保留日志/附件/基建
- **删除**:Activity、ActivityRead、ActivitySignup、ContactGroup、ContactGroupUser、SysDict 实体 + 对应 Repository/Service/Controller(ActivityController、ContactsController、DictController)+ `model/activity/` 全部 + `sql/dormnotice_schema.sql`。
- **保留**:BaseEntity、SysOperationLog、UpFile、BaseAuditListener、ValidationGroups、PageUtils、BasePageQuery/Result、UserContext/UserSysRole/UserType、两切面、BaseApiController、FileController、LogController、ClassService、UserCenterService、FileService、SysOperationLogService。
- **前置修复**:BaseApiController 的 ClassTreeNodeVo import 改指 `model.bsch`。
### 任务 3:新实体与业务(不存账号,存教师 id)
- `entity/Timetable`、`entity/TimetableSlot`(见第三节表设计)。
- `service/ITimetableService + impl`:
- `get(classId)`:按 UserContext.schId + classId 取课表,组装 slots(无数据返回空骨架由前端补默认 10 节)。
- `save(request)`:校验(班级属于本校 via ClassService、时间格式与先后、学科 ∈ 本校学科表、day 列数=7)→ 全量替换 slots,teacher_id=UserContext.userId,冗余 class_name/grade_name。
- `savePhoto(classId, fileId)`:绑定照片(up_file topic_type=timetable),替换时清理旧文件。
- `removePhoto(classId)`:解绑并删文件。
### 任务 4:ClassService 扩展学科接口
- `IClassService.getSubjectList(schId)`:GET `{bschclass}/oapi/sch/getSchSubjectList?schId=`,5 分钟缓存(与学生树同款),返回 `[{id, code, name}]`。失败降级返回空列表并 log.warn。
### 任务 5:TimetableController(`/{platform}/timetable/`,PascalCase 惯例)
| 接口 | 方法 | 说明 |
|---|---|---|
| `/Get` | GET | `?classId=` 返回课表 VO(slots + photoFileId/photoUrl) |
| `/Save` | POST @RequestBody | 整表保存(电子版) |
| `/SavePhoto` | POST | `?classId=&fileId=` 绑定照片 |
| `/RemovePhoto` | POST | `?classId=` 移除照片 |
| `/Subjects` | GET | 本校学科列表 |
- FileController 上传沿用:前端先 `/api/file/Upload` 拿 fileid,再 SavePhoto 绑定;Preview 展示。
### 任务 6:前端改造
1. 新增 `src/types/syllabus.ts`(TimetableVo/SlotVo/SubjectVo/SaveRequest)。
2. 新增 `src/api/module/syllabus.ts`(syllabusApi:Get/Save/SavePhoto/RemovePhoto/Subjects;复用 baseApi.GetClassTree/GetUserInfo —— baseApi 移入本模块或新建 `base.ts`)。
3. 新增 `src/views/syllabus/TimetableEdit.vue`:移植 timetable-site 交互(页签、班级选择、编辑表格、时段分组、新增/删除/恢复节次、预览 Modal+打印、照片 dropzone 上传/替换/移除);保存到后端(保存按钮 + 未保存标记,替代原 localStorage)。
4. routes.ts:删 dorm 路由,新增 `/timetable`(meta.title 课程表编排、modId 占位);`/` 默认进课程表。
5. layout.vue `getMenuIcon`、menuRoute.ts 别名、App.vue 应用名、index.html/vite.config 标题 → 「课程表」。
6. 删除 `views/dorm/`、`api/module/dorm.ts`、`types/dorm.ts`;死组件(GradeClassSel/BschSubjectSelect/UploadImg/TreeNode 等)不再被引用,随构建树摇出产物,暂不物理删除。
### 任务 7:bug 审查与优化(账号 lijing / a123123)
已知待修(本计划内执行):
1. BaseApiController 错误 import activity.ClassTreeNodeVo(任务 2 前置)。
2. 切面切点/排除名单硬编码包名(任务 1 一并替换)。
3. 生产 context-path/库名/sms module-id 残留 dormnotice(任务 1.5)。
4. Dockerfile EXPOSE(10002) 与实际端口(8070) 不一致。
5. dorm.ts `ReceiptFormTemplate` 未导入的类型瑕疵(随 dorm 删除消解)。
6. 前端 `postForm` 双发导致 Spring 参数合并 `"x,x"` 的历史坑——新 syllabus.ts postForm 仅在 isMock 时拼 query,沿用防御。
联调项(需平台在线,代码层先保证):
- CAS 登录 → GetUserInfo/GetUserMod → currentRole → UserContext 填充 → schId 隔离;
- lijing 建课表/换班/预览/打印/照片全流程;操作日志落库抽查。
## 五、实施顺序与验收
| 阶段 | 内容 | 验收 |
|---|---|---|
| 一 | 任务 1+2:改名、删业务、前置修复 | `mvn compile` 通过;全局 grep `dormnotice` 仅剩历史文档 |
| 二 | 任务 3+4+5:实体/服务/接口 | `mvn compile` 通过;Swagger 自查接口形状 |
| 三 | 任务 6:前端页面/路由/API | `npm run build` 通过 |
| 四 | 任务 7:bug 审查修复 + 联调准备 | 清单全过;文档勾选执行状态 |
## 六、风险与说明
1. lijing/a123123 为基础平台(CAS/用户中心)账号,代码中不落库不校验密码;联调依赖平台与班级服务在线。
2. 学科 oapi 若因权限/网络不可用, Subjects 返回空列表并前端提示,不阻断电子课表编辑(学科名仍可显示已存数据)。
3. 平台菜单(GetUserMod)未配「课程表」模块时,前端 `/` 兜底直接进 `/timetable`,菜单缺失不影响直访。
4. 旧 dorm 数据表(activity 等)保留在库中不删,仅代码层不再引用。