# 修复学生导入：姓名与账号字段 — 设计文档

> 日期：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` 编译通过
