diff --git a/doc/interface-doc/ccdi/staff-transfer.md b/doc/interface-doc/ccdi/staff-transfer.md new file mode 100644 index 0000000..8139ef7 --- /dev/null +++ b/doc/interface-doc/ccdi/staff-transfer.md @@ -0,0 +1,210 @@ +# 员工调动管理接口文档 + +## 员工调动导入 + +### 接口信息 + +**接口地址**: `POST /ccdi/staffTransfer/import` + +**请求方式**: POST + +**Content-Type**: multipart/form-data + +### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| file | File | 是 | Excel文件(.xlsx格式) | + +### 响应格式 + +**成功响应**: +```json +{ + "code": 200, + "msg": "导入任务已提交", + "data": { + "taskId": "550e8400-e29b-41d4-a716-446655440000" + } +} +``` + +**字段说明**: +- `code`: 响应码,200表示成功 +- `msg`: 响应消息 +- `data.taskId`: 导入任务ID,用于查询导入进度和结果 + +### 错误情况 + +| 错误类型 | 错误信息示例 | 说明 | HTTP状态码 | +|---------|-------------|------|-----------| +| 员工ID不存在 | 第3行: 员工ID 99999 不存在 | 该员工ID在员工信息表中不存在 | 200 (异步处理) | +| 员工ID为空 | 员工ID不能为空 | Excel中未填写员工ID | 200 (异步处理) | +| 调动类型无效 | 调动类型[xxx]无效 | 调动类型不在字典中 | 200 (异步处理) | +| 部门ID不存在 | 部门ID 999 不存在 | 调动前/后部门ID在部门表中不存在 | 200 (异步处理) | +| 记录重复 | 该员工在2026-01-01的调动记录已存在 | 数据库中已存在相同的调动记录 | 200 (异步处理) | + +**注意**: 导入采用异步处理,即使数据有错误也会返回成功,错误信息需通过任务ID查询。 + +--- + +## 导入状态查询 + +### 接口信息 + +**接口地址**: `GET /ccdi/staffTransfer/import/status/{taskId}` + +**请求方式**: GET + +### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| taskId | String | 是 | 导入任务ID | + +### 响应格式 + +```json +{ + "code": 200, + "msg": "查询成功", + "data": { + "taskId": "550e8400-e29b-41d4-a716-446655440000", + "status": "SUCCESS", + "totalCount": 100, + "successCount": 95, + "failureCount": 5, + "progress": 100, + "message": "成功95条,失败5条" + } +} +``` + +**字段说明**: +- `status`: 导入状态 + - `PROCESSING`: 处理中 + - `SUCCESS`: 全部成功 + - `PARTIAL_SUCCESS`: 部分成功 + - `FAILURE`: 全部失败 +- `totalCount`: 总记录数 +- `successCount`: 成功记录数 +- `failureCount`: 失败记录数 +- `progress`: 进度百分比(0-100) +- `message`: 状态描述 + +--- + +## 失败记录查询 + +### 接口信息 + +**接口地址**: `GET /ccdi/staffTransfer/import/failures/{taskId}` + +**请求方式**: GET + +### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| taskId | String | 是 | 导入任务ID | + +### 响应格式 + +```json +{ + "code": 200, + "msg": "查询成功", + "data": [ + { + "staffId": 99999, + "name": "张三", + "transferType": "调出", + "transferDate": "2026-01-15", + "deptIdBefore": 100, + "deptNameBefore": "原部门", + "deptIdAfter": 200, + "deptNameAfter": "新部门", + "errorMessage": "第3行: 员工ID 99999 不存在" + } + ] +} +``` + +**字段说明**: +- 返回所有导入失败的记录列表 +- 每条记录包含原始数据和 `errorMessage` 字段 +- `errorMessage` 包含具体的错误信息和行号 + +--- + +## 业务逻辑说明 + +### 导入流程 + +1. **上传Excel文件** → 返回任务ID +2. **异步处理**: + - 批量验证员工ID存在性(新增功能) + - 验证调动记录唯一性 + - 验证其他业务规则 + - 批量插入有效数据 +3. **查询状态** → 获取导入进度和结果 +4. **查询失败记录** → 获取详细的错误信息 + +### 员工ID验证规则 + +**批量验证机制**(v2.0新增): +- 在导入开始时,一次性批量查询所有员工ID是否存在 +- 使用 `SELECT staffId FROM ccdi_base_staff WHERE staffId IN (...)` +- 不存在的员工ID记录会被提前标记为失败 +- 失败记录的错误信息格式:`第{行号}行: 员工ID {staffId} 不存在` + +**性能优化**: +- 避免了N+1查询问题 +- 批量查询后,主循环跳过已失败的记录 +- 大数据量场景下性能提升显著 + +--- + +## 错误码说明 + +| 错误码 | 说明 | +|--------|------| +| 200 | 请求成功 | +| 401 | 未授权,请先登录 | +| 403 | 无权限访问 | +| 500 | 服务器内部错误 | + +--- + +## Excel文件格式 + +### 必填字段 + +| 字段名 | 字段说明 | 数据类型 | 示例 | +|--------|----------|----------|------| +| 员工ID | 员工的唯一标识 | Long | 1001 | +| 调动类型 | 调动类型(从字典选择) | String | 调出/调入/内部调动 | +| 调动日期 | 调动生效日期 | Date | 2026-01-15 | +| 调动前部门ID | 调动前的部门ID | Long | 100 | +| 调动后部门ID | 调动后的部门ID | Long | 200 | + +### 可选字段 + +| 字段名 | 字段说明 | 数据类型 | +|--------|----------|----------| +| 姓名 | 员工姓名 | String | +| 备注 | 调动说明 | String | + +--- + +## 更新日志 + +### v2.0 (2026-02-11) +- **新增**: 员工ID存在性批量验证 +- **新增**: 错误信息包含行号 +- **优化**: 批量查询性能优化(避免N+1问题) +- **优化**: 主循环跳过已失败记录 +- **文档**: 更新错误情况说明 + +### v1.0 (2026-01-XX) +- 初始版本