wangziqi/class-schedule-review AGit
main
- assertRosterZipSafe 流式解压限流:单条目 8MB、总量 32MB 硬上限,超限即时中止 - 解压流超时兜底,防畸形 zip 挂起请求 - 工作表数量与行数在 ExcelJS 整体加载前流式预扫描拦截 - sanitizeCellText 补空格/换行公式触发符,keepPlus 支持括号且至少含一位数字 - 解析错误改 RosterParseError(400) 透出可操作提示,不再被 500 吞掉 - main.ts 仅对 /api/classes 路由放宽 JSON body 上限至 2mb
- 科目长度上限收敛到 dto MAX_SUBJECT_LENGTH(30),subjects/subject 加 @MaxLength - ValidateSubjectTeacherHasSubject 对非字符串元素做类型守卫,避免 500 - normalizeTeacherSubjects 去重键小写对齐 MySQL 大小写不敏感 collation - 任课老师逐行保存并包事务:并发 1062 跳过、非重复错误整体回滚 - 非科目角色去掉无事务悲观锁,改查重 + save 捕获 1062 转 400 - 实体 subject 列对齐迁移后 NOT NULL DEFAULT '',唯一索引显式命名 - 提交 DTO 跨字段校验:合计行数不超过文件解析上限,id 需为正整数
- 预览二次校验改 LOWER(TRIM) 归一化,与主查询/commit 路径一致,避免预览判可新建而提交判冲突 - 并发创建同标识学生重查改用锁定读刷新可见性(REPEATABLE READ 旧快照问题) - 批量成员保存撞唯一索引后的恢复:复活行不计入并发跳过,仅新增行且已 active 才算已在本班 - 重试保存逐行执行,避免多行 INSERT 原子失败静默丢行
- 迁移确保 subject NOT NULL DEFAULT '' 并建 (class_id,user_id,role_type,subject) 唯一索引 - 历史多科目值按内容拆分(不依赖列类型),首科目截断与 TS 侧 trim 归一化一致 - 破坏性清理前备份到审计表;暂存表自包含身份列,恢复不依赖原行存活 - 4 列兜底去重防 CREATE UNIQUE INDEX 撞 ER_DUP_ENTRY;GET_LOCK 串行化多实例迁移 - 收敛后启动为纯 no-op,滚动部署不再反复清理 - init.sql 与实体对齐:subject NOT NULL DEFAULT '',唯一索引显式命名
- findTimeConflicts:半选值/无效日期防护、日期未选不误报、坏时间按必定冲突、10 分钟缓冲命名常量 - 教师下拉完全由表单驱动,移除冗余 teacherKey 状态(消除整类双源 desync 问题) - 教师加载加请求序号防过期覆盖 + loading 禁用下拉 + 失败提示不清空表单 - 编辑模式 teacherKey 按实际选项推导,fallback 优先任课老师行并同步科目 - 切班/切老师自动带出:仅真匹配时自动选中,显式科目无人教授时清空防错配 - 选项按复合 key 去重,冲突提示标注基于当前视图
- 提交体条件化:空数组不发送,修复全匹配/全新建两种场景被后端 @ArrayMinSize 拒 400 - 无论是否新建学生都先确认,避免已匹配学生被一键加入无提示 - 学员下拉保留学号/ID 兜底区分同名;科目去重键小写对齐后端唯一索引 - 任课老师空科目前端拦截;教师候选人相关调整
- 共享 PASSWORD_RULES:新增账号与重置密码弹窗统一 - 原 max:72 按字符数校验,多字节密码(如中文 3 字节)会通过前端校验却被服务端 @MaxByteLength(72) 拒绝;改为 TextEncoder 字节数校验
No dependencies set.
The note is not visible to the blocked user.
@MaxByteLength(72) 拒绝;改为 TextEncoder 字节数校验
Pull request closed