spec: fix student import name/phone from dingtalk
This commit is contained in:
@@ -0,0 +1,112 @@
|
|||||||
|
# 修复学生导入:姓名与账号字段 — 设计文档
|
||||||
|
|
||||||
|
> 日期:2026-07-10
|
||||||
|
> 状态:已确认
|
||||||
|
> 关联:PRD 钉钉集成批次 2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 背景
|
||||||
|
|
||||||
|
`batchImportStudents` 创建 Student 时:
|
||||||
|
- `name` 填的是占位符 `dd_${dingUserId}`
|
||||||
|
- `phone` 未设置
|
||||||
|
|
||||||
|
正确行为:
|
||||||
|
- `name` = 钉钉用户真实姓名
|
||||||
|
- `phone` = 钉钉用户手机号;无手机号时填 `dt_${dingUserId}`
|
||||||
|
|
||||||
|
## 2. 方案:前端传用户信息
|
||||||
|
|
||||||
|
前端组织架构树已有 `{ userid, name, mobile }` 数据(来自 `getDeptUsers`),导入时直接传给后端,零额外钉钉 API 调用。
|
||||||
|
|
||||||
|
## 3. 改动清单
|
||||||
|
|
||||||
|
### 3.1 后端 DTO
|
||||||
|
|
||||||
|
**文件:** `apps/server/src/classes/dto/class.dto.ts`
|
||||||
|
|
||||||
|
`BatchImportStudentsDto`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 旧
|
||||||
|
export class BatchImportStudentsDto {
|
||||||
|
dingUserIds: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新
|
||||||
|
export class BatchImportStudentsDto {
|
||||||
|
@IsArray() @ArrayNotEmpty()
|
||||||
|
users: Array<{ dingUserId: string; name: string; mobile?: string }>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`CreateClassDto.dingUserIds` 同改为 `users` 字段。
|
||||||
|
|
||||||
|
### 3.2 后端 Service
|
||||||
|
|
||||||
|
**文件:** `apps/server/src/classes/classes.service.ts`
|
||||||
|
|
||||||
|
`batchImportStudents` 签名改为:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async batchImportStudents(classId: number, users: Array<{
|
||||||
|
dingUserId: string; name: string; mobile?: string;
|
||||||
|
}>): Promise<{ imported: number; skipped: number }>
|
||||||
|
```
|
||||||
|
|
||||||
|
创建 Student 时:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
this.studentRepo.create({
|
||||||
|
name: u.name,
|
||||||
|
phone: u.mobile || `dt_${u.dingUserId}`,
|
||||||
|
status: 'active',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
`create()` 方法中 `dingUserIds` → `users` 透传。
|
||||||
|
|
||||||
|
### 3.3 后端 Controller
|
||||||
|
|
||||||
|
**文件:** `apps/server/src/classes/classes.controller.ts`
|
||||||
|
|
||||||
|
`batchImportStudents` 端点传参改为:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
return this.service.batchImportStudents(+id, dto.users);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 前端
|
||||||
|
|
||||||
|
**文件:** `apps/admin/src/pages/IntegrationConfig/index.tsx`
|
||||||
|
|
||||||
|
`handleJoinClass` 和 `handleCreateClass`:从 `checkedKeys` 反查 `orgTree` 提取完整用户信息,不再只传 ID。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 旧
|
||||||
|
const userIds = checkedKeys.filter(...).map(k => k.replace('user-', ''));
|
||||||
|
api.post('/classes/.../import', { dingUserIds: userIds });
|
||||||
|
|
||||||
|
// 新
|
||||||
|
const checkedUsers = extractCheckedUsers(checkedKeys, orgTree);
|
||||||
|
api.post('/classes/.../import', { users: checkedUsers });
|
||||||
|
```
|
||||||
|
|
||||||
|
`extractCheckedUsers` 工具函数遍历 `orgTree`,匹配 `checkedKeys` 中的 user 节点,返回 `{ dingUserId, name, mobile }[]`。
|
||||||
|
|
||||||
|
## 4. 不改的
|
||||||
|
|
||||||
|
- `DingTalkService.syncOneUser` / `syncAll` — 不受影响
|
||||||
|
- `Student` entity — 字段不变
|
||||||
|
- 数据库 schema — 不变
|
||||||
|
- `StudentDingMapping` — 不受影响
|
||||||
|
|
||||||
|
## 5. 验收标准
|
||||||
|
|
||||||
|
1. 导入新用户后,Student.name 为真实姓名,非 `dd_xxx`
|
||||||
|
2. 有手机号的用户,Student.phone = 手机号
|
||||||
|
3. 无手机号的用户,Student.phone = `dt_<dingUserId>`
|
||||||
|
4. 已存在 mapping 的用户跳过,不重复创建
|
||||||
|
5. 班级创建时传入 `users` 同样生效
|
||||||
|
6. `tsc --noEmit` 编译通过
|
||||||
Reference in New Issue
Block a user