feat(server,web,shared,desktop): 上传超限正确报错 + 两个登录入口都限流 + 作业按天深链,文档与验证脚本同步

服务端加固:
- express.json 上限 2mb → 12mb:表格导入把文件以 base64 放进 JSON(约 4/3 倍),
  8MB 的声明上限原先到 1.5MB 就被拦掉;超限现在由 error 中间件映射成
  413 IMPORT_TOO_LARGE(中文提示"请拆分后分批导入"),不再落进 500 兜底分支抛英文原文;
- loginRateLimiter 同时挂 /auth/login 与 /auth/class-login(班级密码默认 123456,
  班级登录曾是唯一没有暴力破解防护的入口),两个路径共享同一计数器;
- CORS_ORIGIN=* 时启动告警(不拦截启动,避免挡住教室机 file:// 的合法部署);
- 删除已无用的 DEFAULT_STUDENT_PASSWORD;班级 termWeeks 上限 40 → 30,
  与 MAX_TERM_WEEK / weekNumberSchema 对齐(原先对外承诺了系统兑现不了的学期长度)。

Web 端:
- 作业页 ?date= 深链在同路由再推 query 时也生效(watch route.query.date);
- 表格导入对话框适配 8MB 上限与 413 提示。

冒烟与文档:
- 新增 scripts/lib/smoke-class.mjs:验证用临时班级,避免探针通知弹到用户自己的客户端与灵动岛;
- README 与 AGENTS.md 同步本轮全部行为变更(含 schedule source、学生账号清理、凭据门禁)。
This commit is contained in:
LoveChengke committed 2026-10-02 00:25:21 +08:00
1 parent 3880eee08e
commit 20fcca0388
28 files changed
+1649 -915

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ import type { UserRole } from './types.js';
* - `ADMIN` 系统管理员:班级增删改、人员分配、全部数据
* - `HEAD` 班主任(`Class.teacherId`):本班课表 + 本班成绩(含导入)+ 作业/通知/叫人
* - `SUBJECT` 科任老师(`ClassTeacher`):仅作业/通知/叫人
* - `STUDENT` 学生(个人账号或班级账号):只读
* - `STUDENT` 学生(班级账号;个人学生账号已清理):只读
* - `NONE` 与该班级无关
*/
export type ClassRole = 'ADMIN' | 'HEAD' | 'SUBJECT' | 'STUDENT' | 'NONE';
+16 -2
View File
@@ -66,7 +66,7 @@ export interface LoginRequest {
/**
* 登录会话主体。
* - 普通账号(教师/管理员/个人学生):就是用户本身;
* - 普通账号(教师/管理员):就是用户本身;学生个人账号已清理,学生只有名单记录;
* - 班级账号(班级设备):`classSession = true`,此时 `id` 与 `classId` 都是班级 id,
* `name` 是班级名,个人数据由服务端按"全班"范围读写。
*/
@@ -129,12 +129,16 @@ export interface CreateClassRequest {
grade: string;
/** 可选:自定义班级码,留空自动生成 */
code?: string;
/** 本学期教学周数(1~30,仅管理员可调);不传由服务端用默认值 20 */
termWeeks?: number;
/** 仅管理员可指定班主任;不传时由创建者本人担任 */
teacherId?: string;
}
export interface UpdateClassRequest {
name?: string;
grade?: string;
/** 本学期教学周数(1~40,班主任可调) */
/** 本学期教学周数(1~30,仅管理员可调) */
termWeeks?: number;
}
@@ -591,6 +595,16 @@ export interface IslandState {
currentPeriodEnd: string | null;
/** 本轮展示原因:新消息 / 下课后补发 / 紧急插播 / 叫人 */
reason: 'new' | 'after-class' | 'urgent' | 'call' | null;
/**
* 多条通知时是否已点过"展开更多"(展开后显示全部放得下的通知)。
* 由主进程持有:卡片高度与窗口包围盒都由它决定,渲染进程只负责照此渲染。
*/
listExpanded: boolean;
/**
* 展开卡在当前屏幕与停靠位置下的**可用高度上限**(CSS px,已经扣到任务栏/工作区下沿)。
* 渲染进程用它决定"列表能显示几条",主进程用它给窗口包围盒封顶 —— 两边算的是同一个数。
*/
maxCardHeight: number;
updatedAt: number;
}