Files
gongxue-base/docs/superpowers/specs/2026-07-09-dingtalk-import-fixes-design.md

3.2 KiB
Raw Blame History

DingTalk 导入链路修复 — 设计文档

日期2026-07-09
状态:已确认
关联PRD 钉钉集成批次 1/2


1. 背景

DingTalk 用户导入 → 班级标记 → 排课 → 考勤 的链路已基本搭建完成,但存在两个阻塞问题:

  1. 前端: "标为班级"按钮出现在所有部门节点上,包括有子部门的父节点。应该在叶子节点(无子部门、有用户)才显示。
  2. 后端: CampusScopedepartmentId 做数据隔离,但钉钉同步的老师没有 UserDepartment 关联,导致非超管老师看不到学生和考勤数据。

本设计的核心原则:教学域(班级、学生、考勤、排课)不走部门过滤,权限边界是"老师教的班",不是"老师归哪个部门"。


2. 改动清单

2.1 前端:叶子节点判断

文件: apps/admin/src/pages/IntegrationConfig/index.tsx

位置: buildTreeData 回调函数,第 371431 行

改动: 部门节点的标题渲染逻辑改为:

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 编译通过