diff --git a/docs/superpowers/specs/2026-07-09-dingtalk-import-fixes-design.md b/docs/superpowers/specs/2026-07-09-dingtalk-import-fixes-design.md new file mode 100644 index 0000000..3b31be7 --- /dev/null +++ b/docs/superpowers/specs/2026-07-09-dingtalk-import-fixes-design.md @@ -0,0 +1,90 @@ +# DingTalk 导入链路修复 — 设计文档 + +> 日期:2026-07-09 +> 状态:已确认 +> 关联:PRD 钉钉集成批次 1/2 + +--- + +## 1. 背景 + +DingTalk 用户导入 → 班级标记 → 排课 → 考勤 的链路已基本搭建完成,但存在两个阻塞问题: + +1. **前端:** "标为班级"按钮出现在所有部门节点上,包括有子部门的父节点。应该在叶子节点(无子部门、有用户)才显示。 +2. **后端:** `CampusScope` 按 `departmentId` 做数据隔离,但钉钉同步的老师没有 `UserDepartment` 关联,导致非超管老师看不到学生和考勤数据。 + +本设计的核心原则:**教学域(班级、学生、考勤、排课)不走部门过滤,权限边界是"老师教的班",不是"老师归哪个部门"。** + +--- + +## 2. 改动清单 + +### 2.1 前端:叶子节点判断 + +**文件:** `apps/admin/src/pages/IntegrationConfig/index.tsx` + +**位置:** `buildTreeData` 回调函数,第 371–431 行 + +**改动:** 部门节点的标题渲染逻辑改为: + +``` +if (node.children.length === 0 && node.users.length > 0) { + // 叶子节点:显示"标为班级"按钮 或 "班级: xxx [已标记]" +} else { + // 非叶子节点:只显示部门名称 +} +``` + +非叶子节点(有子部门)不显示任何班级标记入口。 + +### 2.2 后端:移除教学域 CampusScope + +**原则:** CampusScope 保留给管理域(宿舍 `OccupanciesService`、房间 `RoomsService`、账单 `BillsService`、费用 `ExpensesService`)——这些按校区/部门隔离数据是合理的。教学域不走部门过滤。 + +#### 2.2.1 StudentsService + +**文件:** `apps/server/src/students/students.service.ts` + +**改动:** +- 移除 `CampusScope` 注入(构造函数参数 `private readonly scope: CampusScope`) +- 移除 `findAll` 方法中的 `await this.scope.filter(where)` 调用 +- `findAll` 直接使用原始 `where` 条件查询 + +**影响:** 有 `student:view` 权限的用户可以看到所有学生,不再按部门隔离。 + +#### 2.2.2 AttendanceService + +**文件:** `apps/server/src/attendance/attendance.service.ts` + +**改动:** +- 移除 `CampusScope` 注入 +- 移除所有 `scope.filter()` / `scope.getScopeDepartmentIds()` 调用 +- 考勤记录查询不再按部门过滤 + +**影响:** 有 `attendance:view` 权限的用户可以看到所有考勤数据。 + +--- + +## 3. 不改的 + +| 模块 | 原因 | +|---|---| +| `ClassesService` | 已不使用 CampusScope | +| `SchedulesService` | 已不使用 CampusScope | +| `OccupanciesService` | 宿舍管理需要部门隔离,保留 | +| `RoomsService` | 房间管理需要部门隔离,保留 | +| `BillsService` | 财务管理需要部门隔离,保留 | +| `ExpensesService` | 费用管理需要部门隔离,保留 | +| `DingTalkService.syncAll` | 同步逻辑不变 | +| `SyncService.importDingTalkUsers` | 导入逻辑不变 | +| RBAC 权限码 | 不动 | + +--- + +## 4. 验收标准 + +1. 钉钉组织架构树中,父部门节点不显示"标为班级"按钮,叶子节点正常显示 +2. 非超管老师登录后,学生列表正常显示所有学生 +3. 非超管老师登录后,考勤页面正常显示所有考勤记录 +4. 宿舍、财务等管理域功能不受影响(部门过滤仍然生效) +5. `tsc --noEmit` 编译通过