1014 lines
36 KiB
Markdown
1014 lines
36 KiB
Markdown
# 报到机接口文档(TrainRegisterApiController)
|
||||
|
|
|
|||
|
|
> **服务模块**:`ruoyi-admin`
|
|||
|
|
> **控制器**:`com.ruoyi.web.controller.api.TrainRegisterApiController`
|
|||
|
|
> **接口前缀**:`/api/register/v1`
|
|||
|
|
> **文档依据**:控制器源码(截至 2026-11-09),字段口径以对应 VO / 数据库字段为准
|
|||
|
|
> **适用对象**:报到机(自助终端)厂商、联调与测试人员
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
|
|||
|
|
- [1. 通用说明](#1-通用说明)
|
|||
|
|
- [1.1 请求地址](#11-请求地址)
|
|||
|
|
- [1.2 鉴权与请求头](#12-鉴权与请求头)
|
|||
|
|
- [1.3 统一响应结构](#13-统一响应结构)
|
|||
|
|
- [1.4 状态码与错误约定](#14-状态码与错误约定)
|
|||
|
|
- [1.5 时间与命名约定](#15-时间与命名约定)
|
|||
|
|
- [2. 接口总览](#2-接口总览)
|
|||
|
|
- [3. 学员信息模块](#3-学员信息模块)
|
|||
|
|
- [3.1 获取学员信息列表](#31-获取学员信息列表)
|
|||
|
|
- [3.2 获取单个学员详情](#32-获取单个学员详情)
|
|||
|
|
- [3.3 获取学员基础信息](#33-获取学员基础信息)
|
|||
|
|
- [3.4 获取学员关联资源](#34-获取学员关联资源)
|
|||
|
|
- [4. 教师信息模块](#4-教师信息模块)
|
|||
|
|
- [4.1 获取教师信息列表](#41-获取教师信息列表)
|
|||
|
|
- [4.2 获取教师基础信息](#42-获取教师基础信息)
|
|||
|
|
- [5. 班级模块](#5-班级模块)
|
|||
|
|
- [5.1 获取进行中班级的未报到学员名单](#51-获取进行中班级的未报到学员名单)
|
|||
|
|
- [6. 宿舍模块](#6-宿舍模块)
|
|||
|
|
- [6.1 获取宿舍布局信息](#61-获取宿舍布局信息)
|
|||
|
|
- [7. 课表模块](#7-课表模块)
|
|||
|
|
- [7.1 获取课程安排(按日期 + 课程类型)](#71-获取课程安排按日期--课程类型)
|
|||
|
|
- [8. 人脸模块](#8-人脸模块)
|
|||
|
|
- [8.1 上传学员人脸照片](#81-上传学员人脸照片)
|
|||
|
|
- [8.2 上传教师人脸照片](#82-上传教师人脸照片)
|
|||
|
|
- [8.3 上传人脸照片(按员工标识自动分发)](#83-上传人脸照片按员工标识自动分发)
|
|||
|
|
- [9. 报到管理模块](#9-报到管理模块)
|
|||
|
|
- [9.1 报到重置](#91-报到重置)
|
|||
|
|
- [10. 附录](#10-附录)
|
|||
|
|
- [10.1 枚举值速查](#101-枚举值速查)
|
|||
|
|
- [10.2 关联数据表](#102-关联数据表)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 通用说明
|
|||
|
|
|
|||
|
|
### 1.1 请求地址
|
|||
|
|
|
|||
|
|
| 项 | 值 |
|
|||
|
|
|---|---|
|
|||
|
|
| 协议 | HTTP(生产建议由网关承载 HTTPS) |
|
|||
|
|
| Host | 部署服务器地址与端口,例如 `http://192.168.1.202:8080` |
|
|||
|
|
| Base Path | `/api/register/v1` |
|
|||
|
|
| 完整示例 | `http://192.168.1.202:8080/api/register/v1/student/list` |
|
|||
|
|
|
|||
|
|
### 1.2 鉴权与请求头
|
|||
|
|
|
|||
|
|
- `SecurityConfig` 中已将 `/api/register/v1/**` 配置为 `permitAll`,**当前所有接口均无需登录令牌**(控制器类注释中提到的 Bearer 鉴权已不再生效)。
|
|||
|
|
- 若生产环境在网关/边缘设备层增加了设备签名(如 HMAC)校验,以网关约定为准,不影响本文档的接口定义。
|
|||
|
|
- 请求头:
|
|||
|
|
|
|||
|
|
| 场景 | Header | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 所有请求 | `Accept: application/json` | 可选 |
|
|||
|
|
| POST 请求 | `Content-Type: application/json` | **必填**,请求体为 JSON |
|
|||
|
|
| 文件/人脸 | 无 | 人脸图片以 base64 字符串放在 JSON 请求体内,不使用 multipart |
|
|||
|
|
|
|||
|
|
### 1.3 统一响应结构
|
|||
|
|
|
|||
|
|
除个别特殊说明外,全部接口返回 `AjaxResult`:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| code | int | 业务状态码,见 1.4 |
|
|||
|
|
| msg | string | 提示信息,成功时为“操作成功”,失败时为错误描述 |
|
|||
|
|
| data | any | 业务数据;失败时可能不存在 |
|
|||
|
|
|
|||
|
|
> 注意:`data` 为 `null` 时部分序列化配置下该字段可能被省略,客户端应做空值兜底。
|
|||
|
|
|
|||
|
|
### 1.4 状态码与错误约定
|
|||
|
|
|
|||
|
|
| code | 含义 | 典型场景 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 200 | 成功 | 正常返回 |
|
|||
|
|
| 500 | 通用业务/参数错误 | 参数缺失、图片解析失败、文件写入失败、业务校验不通过 |
|
|||
|
|
| 601 | 警告 | 预留,本文档接口未使用 |
|
|||
|
|
| 40402 | 学员不存在 | `GET /student/{sId}` 及依赖学员主档的接口(`StudentErrorCode.STUDENT_NOT_FOUND`) |
|
|||
|
|
| 401 | 未认证 | 当前 `/api/register/v1/**` 已放行,正常不会出现 |
|
|||
|
|
|
|||
|
|
**重要约定**:业务异常由全局异常处理器统一捕获,**HTTP 状态码固定为 200**,调用方必须依据响应体中的 `code` 判断成败,不能只看 HTTP 状态。
|
|||
|
|
|
|||
|
|
### 1.5 时间与命名约定
|
|||
|
|
|
|||
|
|
- 服务端 Jackson 时区为 `GMT+8`,日期时间统一格式 `yyyy-MM-dd HH:mm:ss`,纯日期格式 `yyyy-MM-dd`。
|
|||
|
|
- JSON 字段以接口定义为准,部分沿用数据库下划线风格(如 `dorm_room`),属于既有契约,请勿自行转换。
|
|||
|
|
- 学员标识为 `sId`,教师标识为 `tId`;人脸库中教师人员 ID 统一为 `tId + "_teacher"`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 接口总览
|
|||
|
|
|
|||
|
|
| 序号 | 模块 | 方法 | 路径 | 用途 |
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
| 1 | 学员信息 | GET | `/student/list` | 学员主档列表(含报到状态) |
|
|||
|
|
| 2 | 学员信息 | GET | `/student/{sId}` | 单个学员详情(含账号绑定信息) |
|
|||
|
|
| 3 | 学员信息 | GET | `/student/{sId}/base` | 学员基础信息(宿舍/教室/开班/场地) |
|
|||
|
|
| 4 | 学员信息 | GET | `/student/{sId}/resources` | 学员关联资源(在基础信息上增加课程表与课次) |
|
|||
|
|
| 5 | 教师信息 | GET | `/teacher/list` | 教师主档列表(字段结构同学员列表) |
|
|||
|
|
| 6 | 教师信息 | GET | `/teacher/{tId}/base` | 教师基础信息(信息/宿舍/授课课表) |
|
|||
|
|
| 7 | 班级 | GET | `/class/student` | 进行中班级及其未报到学员名单 |
|
|||
|
|
| 8 | 宿舍 | GET | `/dormitory/layout` | 宿舍布局(楼栋→楼层→房间) |
|
|||
|
|
| 9 | 课表 | GET | `/lesson/schedule` | 按日期(可选课程类型)查询课程安排 |
|
|||
|
|
| 10 | 人脸 | POST | `/student/face` | 上传学员人脸并更新头像、补办报到 |
|
|||
|
|
| 11 | 人脸 | POST | `/teacher/face` | 上传教师人脸并更新头像 |
|
|||
|
|
| 12 | 人脸 | POST | `/face` | 按 `employeeId` 后缀自动分发到学员/教师 |
|
|||
|
|
| 13 | 报到管理 | POST | `/report/reset` | 报到重置(解绑人脸 + 清门锁授权 + 复位参训状态) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 学员信息模块
|
|||
|
|
|
|||
|
|
### 3.1 获取学员信息列表
|
|||
|
|
|
|||
|
|
**用途**:报到机启动或刷新时拉取全部学员主档,用于本地人员检索、人脸比对名单准备;每条记录额外补入该学员最新一条报到记录的参训状态与报到时间。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/student/list`
|
|||
|
|
- **请求参数**:无
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"sId": "S20260001",
|
|||
|
|
"sName": "张三",
|
|||
|
|
"personNo": "P0001",
|
|||
|
|
"sGender": "男",
|
|||
|
|
"sBirth": "1998-05-12",
|
|||
|
|
"deptName": "供电段",
|
|||
|
|
"cardNo": "C0001",
|
|||
|
|
"sPhone": "13800000001",
|
|||
|
|
"sEmail": "zhangsan@example.com",
|
|||
|
|
"idCardMasked": "210***********1234",
|
|||
|
|
"idCardLast4": "1234",
|
|||
|
|
"sourceType": 1,
|
|||
|
|
"status": 1,
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/xxx.png",
|
|||
|
|
"dutyLevel": null,
|
|||
|
|
"id": 1,
|
|||
|
|
"deptId": 103,
|
|||
|
|
"enrollmentStatus": 0,
|
|||
|
|
"joinTime": null
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明(`StudentItemVO`)**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| sId | string | 学员唯一标识(主键引用口径) |
|
|||
|
|
| sName | string | 姓名 |
|
|||
|
|
| personNo | string | 人员编号 |
|
|||
|
|
| sGender | string | 性别 |
|
|||
|
|
| sBirth | string | 出生日期 `yyyy-MM-dd` |
|
|||
|
|
| deptName | string | 所属部门/车间名称 |
|
|||
|
|
| cardNo | string | 卡号 |
|
|||
|
|
| sPhone / sEmail | string | 手机号 / 邮箱 |
|
|||
|
|
| idCardMasked / idCardLast4 | string | 脱敏身份证 / 后四位(明文身份证不下发) |
|
|||
|
|
| sourceType | int | 学员来源类型 |
|
|||
|
|
| status | int | 档案状态 |
|
|||
|
|
| avatar | string | 头像可访问路径(相对资源前缀) |
|
|||
|
|
| id / deptId | long | 自增编号 / 部门ID |
|
|||
|
|
| enrollmentStatus | int | 参训状态:0待报到、1已报到、2请假、3放弃、4已完成(取最新一条报名记录) |
|
|||
|
|
| joinTime | datetime | 报到时间(取最新一条报名记录,未报到为 null) |
|
|||
|
|
| extractStatus / extractTime / extractMsg / photoMd5 / featureData / featureMd5 / featureAlgoVersion / featureSize | — | 人脸特征提取的内部扩展字段,报到机通常无需使用,多为 null |
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 数据库异常 | 500 | 系统异常提示 |
|
|||
|
|
| 查询结果为空 | 200 | `data: []`(空数组,非错误) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3.2 获取单个学员详情
|
|||
|
|
|
|||
|
|
**用途**:按 `sId` 查询单个学员的完整档案,并附带其系统账号绑定状态,供报到机核对身份或人工处理。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/student/{sId}`
|
|||
|
|
- **请求参数(Path)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| sId | string | 是 | 学员唯一标识 |
|
|||
|
|
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"sId": "S20260001",
|
|||
|
|
"sName": "张三",
|
|||
|
|
"personNo": "P0001",
|
|||
|
|
"sGender": "男",
|
|||
|
|
"sBirth": "1998-05-12",
|
|||
|
|
"deptName": "供电段",
|
|||
|
|
"cardNo": "C0001",
|
|||
|
|
"sPhone": "13800000001",
|
|||
|
|
"sEmail": "zhangsan@example.com",
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/xxx.png",
|
|||
|
|
"faceRef": null,
|
|||
|
|
"remark": null,
|
|||
|
|
"createBy": "admin",
|
|||
|
|
"createTime": "2026-09-01 09:00:00",
|
|||
|
|
"userId": 105,
|
|||
|
|
"userName": "student01",
|
|||
|
|
"nickName": "张三",
|
|||
|
|
"accountBindingStatus": 1
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**:`StudentAdminVO = StudentItemVO + StudentDetailVO + 账号绑定字段`
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| (基础字段) | — | 同 3.1 学员列表字段 |
|
|||
|
|
| faceRef | string | 人脸参考标识 |
|
|||
|
|
| remark | string | 备注 |
|
|||
|
|
| createBy / createTime | string / datetime | 建档人 / 建档时间 |
|
|||
|
|
| userId | long | 绑定的系统用户ID(未绑定为 null) |
|
|||
|
|
| userName | string | 绑定的系统登录账号 |
|
|||
|
|
| nickName | string | 绑定的用户昵称 |
|
|||
|
|
| accountBindingStatus | int | 账号关联状态:0未关联、1已关联 |
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 学员不存在 | 40402 | 学员不存在 |
|
|||
|
|
| `sId` 为空 | 40402 / 500 | 学员不存在(按未命中处理) |
|
|||
|
|
|
|||
|
|
> 说明:源码中 `detail == null` 分支返回 `data: null`,但底层 `selectStudentDetail` 在未命中时会抛业务异常,因此实际表现为 `code=40402`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3.3 获取学员基础信息
|
|||
|
|
|
|||
|
|
**用途**:报到机刷脸/刷卡识别学员后,展示该学员的**个人基础信息、所属开班、当前宿舍床位、上课教室、实训场地**,用于报到确认页。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/student/{sId}/base`
|
|||
|
|
- **请求参数(Path)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| sId | string | 是 | 学员唯一标识 |
|
|||
|
|
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
- **数据来源**:班级优先取该学员最新报到记录(`train_class_report`)中的 `plan_id`,缺失时回落到报名关系(`train_enrollment`)中最新的班级;教室取该班排课课次(`train_lesson`)中**首个带教室**的课次,实训场地取**首个带场地**的课次(两者可能来自不同课次)。
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"studInfo": {
|
|||
|
|
"sId": "S20260001",
|
|||
|
|
"sName": "张三",
|
|||
|
|
"sPhone": "13800000001",
|
|||
|
|
"sGender": "男",
|
|||
|
|
"deptName": "供电段",
|
|||
|
|
"personNo": "P0001"
|
|||
|
|
},
|
|||
|
|
"classPlan": {
|
|||
|
|
"planId": "PLAN-2026-01",
|
|||
|
|
"planName": "2026年秋季高铁房建设施高级研修班",
|
|||
|
|
"startTime": "2026-09-15 08:30:00",
|
|||
|
|
"endTime": "2026-09-30 17:30:00"
|
|||
|
|
},
|
|||
|
|
"dormitory": {
|
|||
|
|
"dormId": "DORM-0101",
|
|||
|
|
"bedNo": "2",
|
|||
|
|
"dormBuilding": "1号楼",
|
|||
|
|
"dormRoom": "101"
|
|||
|
|
},
|
|||
|
|
"classroom": {
|
|||
|
|
"classRoomId": "CR-001",
|
|||
|
|
"roomLocation": "实训基地A栋201",
|
|||
|
|
"roomName": "第一理论教室"
|
|||
|
|
},
|
|||
|
|
"trainingSite": {
|
|||
|
|
"siteId": "TS-001",
|
|||
|
|
"siteLocation": "实训基地B栋",
|
|||
|
|
"siteName": "接触网实训场",
|
|||
|
|
"major": "接触网工"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| studInfo | object | 学员精简信息:`sId`、`sName`、`sPhone`、`sGender`、`deptName`、`personNo` |
|
|||
|
|
| classPlan | object \| null | 所属开班:`planId`、`planName`、`startTime`、`endTime`;未分配班级时为 null |
|
|||
|
|
| dormitory | object | 宿舍:`dormId`、`bedNo`(有住宿记录时)、`dormBuilding`、`dormRoom`;未分配宿舍时字段可能为 null |
|
|||
|
|
| classroom | object \| null | 上课教室:`classRoomId`、`roomLocation`、`roomName`;该班无教室课次时为 null |
|
|||
|
|
| trainingSite | object \| null | 实训场地:`siteId`、`siteLocation`、`siteName`、`major`;该班无场地课次时为 null |
|
|||
|
|
|
|||
|
|
> 本接口**不返回** `courses` 与 `lesson` 明细(源码中已注释关闭),需要课表请调用 3.4 或 7.1。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 学员不存在 | 40402 | 学员不存在 |
|
|||
|
|
| 学员未分配班级/宿舍 | 200 | 对应字段为 `null`(不是错误) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3.4 获取学员关联资源
|
|||
|
|
|
|||
|
|
**用途**:在 3.3 的基础上**额外返回该学员所在班级的课程清单与课次明细**,供报到机展示“我的课程 / 我的课表”。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/student/{sId}/resources`
|
|||
|
|
- **请求参数(Path)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| sId | string | 是 | 学员唯一标识 |
|
|||
|
|
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
|
|||
|
|
**响应示例**(在 3.3 的 `data` 基础上增加两个字段)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"studInfo": { "sId": "S20260001", "sName": "张三", "sPhone": "13800000001", "sGender": "男", "deptName": "供电段", "personNo": "P0001" },
|
|||
|
|
"classPlan": { "planId": "PLAN-2026-01", "planName": "2026年秋季高铁房建设施高级研修班", "startTime": "2026-09-15 08:30:00", "endTime": "2026-09-30 17:30:00" },
|
|||
|
|
"courses": [
|
|||
|
|
{ "cId": "C0001", "cName": "高铁站房巡检" }
|
|||
|
|
],
|
|||
|
|
"lesson": [
|
|||
|
|
{ "startTime": "2026-09-16 09:00:00", "endTime": "2026-09-16 11:30:00", "planCourseId": 1, "cName": "高铁站房巡检" }
|
|||
|
|
],
|
|||
|
|
"dormitory": { "dormId": "DORM-0101", "bedNo": "2", "dormBuilding": "1号楼", "dormRoom": "101" },
|
|||
|
|
"classroom": { "classRoomId": "CR-001", "roomLocation": "实训基地A栋201", "roomName": "第一理论教室" },
|
|||
|
|
"trainingSite": { "siteId": "TS-001", "siteLocation": "实训基地B栋", "siteName": "接触网实训场", "major": "接触网工" }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**新增字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| courses | array | 该班已配置课程:`cId`(课程ID)、`cName`(课程名称);无班级时为 null |
|
|||
|
|
| lesson | array | 该班全部课次:`startTime`、`endTime`、`planCourseId`、`cName`;无课次时为 null 或空数组 |
|
|||
|
|
|
|||
|
|
> `lesson` 元素**不含**教师与场地字段;如需教师/场地/班牌信息,请使用 7.1 `GET /lesson/schedule`。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 学员不存在 | 40402 | 学员不存在 |
|
|||
|
|
| 无班级 | 200 | `classPlan`、`courses`、`lesson` 为 null |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 教师信息模块
|
|||
|
|
|
|||
|
|
### 4.1 获取教师信息列表
|
|||
|
|
|
|||
|
|
**用途**:拉取全部教师主档,字段结构与学员列表**完全一致**,便于报到机用同一套解析逻辑处理两类人员。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/teacher/list`
|
|||
|
|
- **请求参数**:无
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
|
|||
|
|
**字段映射规则**
|
|||
|
|
|
|||
|
|
| 输出字段 | 取值来源 |
|
|||
|
|
|---|---|
|
|||
|
|
| sId | `tId + "_teacher"`(与人脸库教师 employee_id 口径一致) |
|
|||
|
|
| sName | `train_teacher.t_name` |
|
|||
|
|
| personNo / sGender / sBirth / deptName / cardNo / sPhone / sEmail / status / avatar / id | `train_teacher` 对应字段 |
|
|||
|
|
| enrollmentStatus | `train_teacher.enrollment_status`(0待报到/1已报到/2请假/3放弃/4已完成) |
|
|||
|
|
| joinTime | `train_teacher.join_time`(未报到为 null) |
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"sId": "T101_teacher",
|
|||
|
|
"sName": "李老师",
|
|||
|
|
"personNo": "T0001",
|
|||
|
|
"sGender": "男",
|
|||
|
|
"deptName": "供电教研室",
|
|||
|
|
"sPhone": "13900000001",
|
|||
|
|
"status": 1,
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/teacher.png",
|
|||
|
|
"id": 3,
|
|||
|
|
"enrollmentStatus": 1,
|
|||
|
|
"joinTime": "2026-09-14 09:10:00"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 无教师数据 | 200 | `data: []` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4.2 获取教师基础信息
|
|||
|
|
|
|||
|
|
**用途**:教师刷脸后展示**教师基本信息、当前宿舍、授课课表**。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/teacher/{tId}/base`
|
|||
|
|
- **请求参数(Path)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| tId | string | 是 | 教师工号;**支持传入 `tId + "_teacher"`**,服务端会自动截去后缀 |
|
|||
|
|
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"teacherInfo": {
|
|||
|
|
"tId": "T101",
|
|||
|
|
"tName": "李老师",
|
|||
|
|
"tPhone": "13900000001",
|
|||
|
|
"tGender": "男",
|
|||
|
|
"deptName": "供电教研室",
|
|||
|
|
"personNo": "T0001",
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/teacher.png"
|
|||
|
|
},
|
|||
|
|
"dormitory": {
|
|||
|
|
"dormId": "DORM-0203",
|
|||
|
|
"bedNo": "1",
|
|||
|
|
"dormBuilding": "2号楼",
|
|||
|
|
"dormRoom": "203"
|
|||
|
|
},
|
|||
|
|
"lesson": [
|
|||
|
|
{
|
|||
|
|
"lessonId": 101,
|
|||
|
|
"planCourseId": 1,
|
|||
|
|
"courseName": "高铁站房巡检",
|
|||
|
|
"tId": "T101",
|
|||
|
|
"teacherName": "李老师",
|
|||
|
|
"startTime": "2026-09-16 09:00:00",
|
|||
|
|
"endTime": "2026-09-16 11:30:00",
|
|||
|
|
"venueType": 1,
|
|||
|
|
"classRoomId": "CR-001",
|
|||
|
|
"classRoomName": "第一理论教室",
|
|||
|
|
"siteId": null,
|
|||
|
|
"siteName": null,
|
|||
|
|
"venueName": "第一理论教室",
|
|||
|
|
"boardSn": "BOARD-SN-001",
|
|||
|
|
"remark": null
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| teacherInfo | object \| null | 教师不存在时为 null;字段:`tId`、`tName`、`tPhone`、`tGender`、`deptName`、`personNo`、`avatar` |
|
|||
|
|
| dormitory | object | `dormId`、`bedNo`(有住宿时)、`dormBuilding`、`dormRoom` |
|
|||
|
|
| lesson | array | 该教师全部授课课次(按开始时间升序),元素为 `TimetableLessonItemVO`,字段见下表 |
|
|||
|
|
|
|||
|
|
**`lesson` 元素字段(TimetableLessonItemVO)**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| lessonId | long | 课次ID |
|
|||
|
|
| planCourseId | long | 计划课程实例ID |
|
|||
|
|
| courseName | string | 课程名称 |
|
|||
|
|
| tId | string | 教师工号 |
|
|||
|
|
| teacherName | string | 教师姓名 |
|
|||
|
|
| startTime / endTime | datetime | 课次起止时间 |
|
|||
|
|
| venueType | int | 场地类型:1普通教室、2实训场地 |
|
|||
|
|
| classRoomId / classRoomName | string | 教室ID / 名称(venueType=1 时有效) |
|
|||
|
|
| siteId / siteName | string | 实训场地ID / 名称(venueType=2 时有效) |
|
|||
|
|
| venueName | string | 场地聚合展示名(教室名或场地名) |
|
|||
|
|
| boardSn | string | 电子班牌 SN;未唯一绑定该教室时为 null |
|
|||
|
|
| remark | string | 课次备注 |
|
|||
|
|
|
|||
|
|
> 该接口不按日期过滤,返回教师全部课次。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| tId 不存在 | 200 | `teacherInfo: null`、`lesson: []` |
|
|||
|
|
| 教师无住宿/无课次 | 200 | 对应字段为空对象/空数组 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 班级模块
|
|||
|
|
|
|||
|
|
### 5.1 获取进行中班级的未报到学员名单
|
|||
|
|
|
|||
|
|
**用途**:报到机按班级展示**待报到学员**,用于现场点名/呼叫报到。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/class/student`
|
|||
|
|
- **请求参数**:无
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
- **筛选口径**:班级 `plan_status = 1`(进行中);学员 `enrollment_status = 0`(待报到)
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": [
|
|||
|
|
{
|
|||
|
|
"planId": "PLAN-2026-01",
|
|||
|
|
"planName": "2026年秋季高铁房建设施高级研修班",
|
|||
|
|
"classId": "CLASS-01",
|
|||
|
|
"className": "房建一班",
|
|||
|
|
"students": [
|
|||
|
|
{ "sId": "S20260001", "sName": "张三", "deptId": 103, "deptName": "供电段" }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| planId / planName | string | 培训班ID / 名称 |
|
|||
|
|
| classId / className | string | 班级ID / 名称 |
|
|||
|
|
| students | array | 未报到学员:`sId`、`sName`、`deptId`、`deptName` |
|
|||
|
|
|
|||
|
|
**容错说明**:单个学员主档缺失时不会中断整体返回,改用报名记录(`train_enrollment`)中的姓名/部门冗余字段兜底,此时 `deptId` 为 null。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 无进行中班级 | 200 | `data: []` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 宿舍模块
|
|||
|
|
|
|||
|
|
### 6.1 获取宿舍布局信息
|
|||
|
|
|
|||
|
|
**用途**:报到机展示宿舍楼栋—楼层—房间的床位占用情况(如“已分配数/总床位数”)。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/dormitory/layout`
|
|||
|
|
- **请求参数**:无
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
- **统计口径**:已分配数 = `train_accommodation` 中住宿状态为 0(预分配)、1(已入住)的记录数;总床位 = 房间核定容量 `capacity`
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"1号楼": {
|
|||
|
|
"1层": {
|
|||
|
|
"101": { "id": 10, "dorm_room": "101", "accommodation": "2/4" }
|
|||
|
|
},
|
|||
|
|
"未标注楼层": {
|
|||
|
|
"102": { "id": 11, "dorm_room": "102", "accommodation": "0/2" }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 层级 | 键 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 一级 | 楼栋名称 | `dorm_building`,为空的数据会被跳过 |
|
|||
|
|
| 二级 | 楼层 | `dorm_floor`,为空时固定为 `未标注楼层` |
|
|||
|
|
| 三级 | 房间号 | `dorm_room` |
|
|||
|
|
| 叶子对象 | id | 房间自增编号 |
|
|||
|
|
| | dorm_room | 房间号(下划线命名,保持既有契约) |
|
|||
|
|
| | accommodation | `已分配床位数/总床位数` 字符串,如 `2/4` |
|
|||
|
|
|
|||
|
|
> 返回使用 `LinkedHashMap`,键顺序与 SQL 排序(楼栋→楼层→房间号)一致;无宿舍数据时 `data: {}`。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 无宿舍数据 | 200 | `data: {}` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 课表模块
|
|||
|
|
|
|||
|
|
### 7.1 获取课程安排(按日期 + 课程类型)
|
|||
|
|
|
|||
|
|
**用途**:查询指定自然日的课程安排,按**日期为键**分组返回课程名称、课程类型、上课地点、上课教师等信息,供报到机/班牌展示当日课表。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`GET /api/register/v1/lesson/schedule`
|
|||
|
|
- **请求参数(Query)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
| startTime | string | 否 | 当天(北京时间) | 课程开始时间,对应 `train_lesson.start_time`。支持 `yyyy-MM-dd`、`yyyy-MM-dd HH:mm:ss`、`yyyy/MM/dd`、ISO-8601(`T` 分隔、`Z` 结尾、`+08:00` 偏移)、10 位秒级 / 13 位毫秒级时间戳;服务端取该时间所在自然日 |
|
|||
|
|
| courseType | string | 否 | 不筛选 | 课程类型,对应 `train_course.c_type`:**`1` = 理论**、**`2` = 实训**。缺省或空串返回当日全部类型;传其它值返回参数错误 |
|
|||
|
|
|
|||
|
|
- **请求体**:不适用
|
|||
|
|
- **查询范围**:`train_lesson` 为主表,关联 `train_plan_course`、`train_course`、`train_teacher`、`train_classroom_info`、`train_training_site`、`train_class_plan`;日期区间为 `[当日 00:00:00, 次日 00:00:00)`,由 SQL `STR_TO_DATE` 在库内生成(不受应用 JVM 时区影响);培训班为逻辑删除时不参与过滤(课表属于已发生的教学事实)。
|
|||
|
|
|
|||
|
|
**请求示例**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
GET /api/register/v1/lesson/schedule
|
|||
|
|
GET /api/register/v1/lesson/schedule?startTime=2026-11-09
|
|||
|
|
GET /api/register/v1/lesson/schedule?startTime=2026-11-09&courseType=1
|
|||
|
|
GET /api/register/v1/lesson/schedule?startTime=2026-11-09T09:00:00&courseType=2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"2026-11-09": [
|
|||
|
|
{
|
|||
|
|
"id": 101,
|
|||
|
|
"name": "高铁站房巡检",
|
|||
|
|
"courseType": "1",
|
|||
|
|
"venueType": 1,
|
|||
|
|
"startTime": "2026-11-09 09:00:00",
|
|||
|
|
"endTime": "2026-11-09 11:30:00",
|
|||
|
|
"teacher": "李老师",
|
|||
|
|
"classroom": "第一理论教室",
|
|||
|
|
"planName": "2026年秋季高铁房建设施高级研修班"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": 102,
|
|||
|
|
"name": "接触网实操",
|
|||
|
|
"courseType": "2",
|
|||
|
|
"venueType": 2,
|
|||
|
|
"startTime": "2026-11-09 14:00:00",
|
|||
|
|
"endTime": "2026-11-09 16:30:00",
|
|||
|
|
"teacher": "王老师",
|
|||
|
|
"classroom": "接触网实训场",
|
|||
|
|
"planName": "2026年秋季高铁房建设施高级研修班"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`data` 结构说明**
|
|||
|
|
|
|||
|
|
| 层级 | 说明 |
|
|||
|
|
|---|---|
|
|||
|
|
| 键 | 日期字符串 `yyyy-MM-dd`(按课次开始时间的北京时间自然日分组,升序) |
|
|||
|
|
| 值 | 该日课程数组,按 `startTime`、`id` 升序 |
|
|||
|
|
|
|||
|
|
**课程元素字段(`CourseScheduleItemVO`)**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| id | long | 课次ID(`train_lesson.lesson_id`) |
|
|||
|
|
| name | string | 课程名称(`train_course.c_name`) |
|
|||
|
|
| courseType | string | 课程类型,与 `train_course.c_type` 一致:`1` 理论、`2` 实训;课程缺失或为空时为 null |
|
|||
|
|
| venueType | int | 课次场地类型:1 普通教室、2 实训场地 |
|
|||
|
|
| startTime / endTime | datetime | 课次起止时间 `yyyy-MM-dd HH:mm:ss` |
|
|||
|
|
| teacher | string | 上课教师姓名(`train_teacher.t_name`) |
|
|||
|
|
| classroom | string | 上课地点:`venueType=1` 取教室名称,`venueType=2` 取实训场地名称 |
|
|||
|
|
| planName | string | 所属培训班名称(`train_class_plan.plan_name`) |
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| startTime 格式无法识别 | 500 | `startTime 格式不正确,支持 yyyy-MM-dd / yyyy-MM-dd HH:mm:ss / ISO-8601,示例:2026-11-09` | 例如传入 `2026年11月9日` |
|
|||
|
|
| courseType 非 1/2 | 500 | `courseType 仅支持 1(理论)或 2(实训)` | 例如传入 `理论`、`3` |
|
|||
|
|
| 当日无课程 | 200 | `data: {}` | 空对象,非错误 |
|
|||
|
|
| 该类型当日无课程 | 200 | `data: {}` | 加了 `courseType` 后无匹配 |
|
|||
|
|
|
|||
|
|
> 服务端会输出日志 `lessonSchedule 课程安排查询 day=..., courseType=..., rows=...`,排障时可直接用 `rows` 区分“SQL 未命中”与“命中但未返回”。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 人脸模块
|
|||
|
|
|
|||
|
|
### 8.1 上传学员人脸照片
|
|||
|
|
|
|||
|
|
**用途**:报到机采集学员人脸 → 转 PNG 落盘 → 更新 `train_student.avatar` → 同步到人脸识别设备 → 回写报到状态并办理门锁入住(若已分配宿舍)。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`POST /api/register/v1/student/face`
|
|||
|
|
- **请求头**:`Content-Type: application/json`
|
|||
|
|
|
|||
|
|
**请求体**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| sId | string | 是 | 学员唯一标识,同时作为人脸库 `employee_id` |
|
|||
|
|
| faceImage | string | 是 | base64 人脸图片,可带 `data:image/png;base64,` 前缀;服务端统一转码为 PNG |
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"sId": "S20260001",
|
|||
|
|
"faceImage": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**业务副作用**(按顺序)
|
|||
|
|
|
|||
|
|
1. 图片解码并保存到 `profile/upload/yyyy/MM/dd/{uuid}.png`,路径写入 `train_student.avatar`
|
|||
|
|
2. 调用人脸设备新增/更新人员(`employee_id = sId`)
|
|||
|
|
3. 回查该学员报名记录,将**第一条**记录的参训状态置为 1(已报到)并记录报到时间
|
|||
|
|
4. 若存在有效住宿记录,调用门禁入住接口(`/openapi/iot/stay/checkin`)下发入住授权
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"sId": "S20260001",
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/9f1c....png",
|
|||
|
|
"faceSync": "success",
|
|||
|
|
"lockCheckin": { "code": 200, "msg": "入住成功" },
|
|||
|
|
"lockAuthId": "",
|
|||
|
|
"joinTime": "2026-11-09 09:12:33"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| sId | string | 学员标识 |
|
|||
|
|
| avatar | string | 头像可访问路径 |
|
|||
|
|
| faceSync | string | 人脸设备同步结果:`success`、`failed`、`skipped` |
|
|||
|
|
| faceMsg | string | 仅 `faceSync=failed` 时出现,失败原因(设备无响应/异常信息) |
|
|||
|
|
| lockCheckin | object | 门锁入住接口返回结果;无有效住宿时不返回 |
|
|||
|
|
| lockAuthId | string | 预留字段,固定空串 |
|
|||
|
|
| joinTime | datetime | 实际报到时间;无住宿时可能不返回 |
|
|||
|
|
| (设备扩展字段) | any | 设备成功时其返回的 `data` 会被并入本层 |
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 缺少 sId 或 faceImage | 500 | 参数缺失:sId 与 faceImage 均为必填 |
|
|||
|
|
| sId 为空串 | 500 | sId 不能为空 |
|
|||
|
|
| 图片非法/无法解码 | 500 | 图片解析失败:{具体原因} |
|
|||
|
|
| 目录创建失败 | 500 | 创建存储目录失败 |
|
|||
|
|
| 文件写入失败 | 500 | 图片写入失败:{具体原因} |
|
|||
|
|
| 学员不存在或更新 0 行 | 500 | 学员不存在或更新失败 |
|
|||
|
|
| 设备同步失败 | 200 | 仍返回成功,`faceSync=failed` + `faceMsg`(头像已保存) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 8.2 上传教师人脸照片
|
|||
|
|
|
|||
|
|
**用途**:教师人脸采集与入库,更新 `train_teacher.avatar`,并同步人脸设备(`employee_id = tId + "_teacher"`)。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`POST /api/register/v1/teacher/face`
|
|||
|
|
- **请求头**:`Content-Type: application/json`
|
|||
|
|
|
|||
|
|
**请求体**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| teacherId | string | 是 | 教师工号(`train_teacher.t_id`),**不要**带 `_teacher` 后缀 |
|
|||
|
|
| faceImage | string | 是 | base64 人脸图片,可带 data URI 前缀 |
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"teacherId": "T101",
|
|||
|
|
"faceImage": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**业务差异**:教师无开班报名记录,**不做报到状态更新**;仅当教师已有有效住宿且已生成门锁流水号时,补发一次入住授权(有效期 15 天)。
|
|||
|
|
|
|||
|
|
**响应示例**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"tId": "T101",
|
|||
|
|
"avatar": "/profile/upload/2026/11/09/ab34....png",
|
|||
|
|
"faceSync": "success",
|
|||
|
|
"lockCheckin": { "code": 200, "msg": "入住成功" },
|
|||
|
|
"lockAuthId": ""
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**:`tId`、`avatar`、`faceSync`、`faceMsg`(失败时)、`lockCheckin`(有住宿且门锁可用时)、`lockAuthId`(固定空串)、设备扩展字段合并规则同上。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 缺少 teacherId 或 faceImage | 500 | 参数缺失:teacherId 与 faceImage 均为必填 |
|
|||
|
|
| teacherId 为空串 | 500 | teacherId 不能为空 |
|
|||
|
|
| 图片非法/无法解码 | 500 | 图片解析失败:{具体原因} |
|
|||
|
|
| 目录/文件写入失败 | 500 | 创建存储目录失败 / 图片写入失败:{具体原因} |
|
|||
|
|
| 教师不存在或更新 0 行 | 500 | 教师不存在或更新失败 |
|
|||
|
|
| 设备同步失败 | 200 | `faceSync=failed` + `faceMsg`(头像已保存) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 8.3 上传人脸照片(按员工标识自动分发)
|
|||
|
|
|
|||
|
|
**用途**:统一入口。按 `employeeId` 后缀自动路由,设备侧无需区分学员/教师接口。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`POST /api/register/v1/face`
|
|||
|
|
- **请求头**:`Content-Type: application/json`
|
|||
|
|
|
|||
|
|
**请求体**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| employeeId | string | 是 | 人脸库人员ID。以 `_teacher` 结尾 → 视为教师(去掉后缀即 `tId`);其它 → 视为学员 `sId` |
|
|||
|
|
| faceImage | string | 是 | base64 人脸图片 |
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"employeeId": "T101_teacher",
|
|||
|
|
"faceImage": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**分发规则**
|
|||
|
|
|
|||
|
|
| 判定 | 路由 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `employeeId` 以 `_teacher` 结尾 | → 8.2 教师人脸上传 | `tId = employeeId` 去掉后缀;后缀匹配区分大小写、不做 trim |
|
|||
|
|
| 其它 | → 8.1 学员人脸上传 | `sId = employeeId` |
|
|||
|
|
|
|||
|
|
**响应**:直接透传被调用接口(8.1 / 8.2)的响应体,结构与之一致。
|
|||
|
|
|
|||
|
|
**错误场景**
|
|||
|
|
|
|||
|
|
| 场景 | code | msg |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 缺少 employeeId 或 faceImage | 500 | 参数缺失:employeeId 与 faceImage 均为必填 |
|
|||
|
|
| employeeId 为空串 | 500 | employeeId 不能为空 |
|
|||
|
|
| employeeId 仅为 `_teacher`(工号为空) | 500 | employeeId 非法:教师工号(tId)不能为空 |
|
|||
|
|
| 后续流程失败 | 500 / 200 | 同 8.1 / 8.2 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 报到管理模块
|
|||
|
|
|
|||
|
|
### 9.1 报到重置
|
|||
|
|
|
|||
|
|
**用途**:误点他人信息导致人脸错绑时的补救接口。按顺序执行:**解绑人脸 → 清除门锁入住授权 → 参训状态复位为 0(待报到) → 清空学员头像**。宿舍分配记录保留,不做退宿。
|
|||
|
|
|
|||
|
|
- **方法 / 路径**:`POST /api/register/v1/report/reset`
|
|||
|
|
- **请求头**:`Content-Type: application/x-www-form-urlencoded`(参数通过 Query 传递,无请求体)
|
|||
|
|
|
|||
|
|
**请求参数(Query)**
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| planId | string | 是 | 培训班ID(`train_enrollment.plan_id`) |
|
|||
|
|
| studentId | string | 是 | 学员ID(`train_student.s_id`) |
|
|||
|
|
|
|||
|
|
**请求示例**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
POST /api/register/v1/report/reset?planId=PLAN-2026-01&studentId=S20260001
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**响应示例(成功)**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "报到重置成功",
|
|||
|
|
"data": {
|
|||
|
|
"planId": "PLAN-2026-01",
|
|||
|
|
"studentId": "S20260001",
|
|||
|
|
"enrollmentId": 900001,
|
|||
|
|
"previousStatus": 1,
|
|||
|
|
"faceUnbind": "success",
|
|||
|
|
"lockCheckout": "success",
|
|||
|
|
"lockApiBizNo": "LOCK20261109001",
|
|||
|
|
"currentStatus": 0,
|
|||
|
|
"alreadyReset": false,
|
|||
|
|
"accommodationKept": true,
|
|||
|
|
"avatarCleared": true,
|
|||
|
|
"avatarSId": "S20260001"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**字段说明**
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| planId / studentId | string | 入参回显 |
|
|||
|
|
| enrollmentId | long | 参训记录ID |
|
|||
|
|
| previousStatus | int | 重置前参训状态 |
|
|||
|
|
| faceUnbind | string | `success`(人脸解绑成功) |
|
|||
|
|
| lockCheckout | string | `success`,或 `skipped: 无有效住宿记录` / `skipped: 缺少门锁业务流水号与宿舍信息` |
|
|||
|
|
| lockApiBizNo | string | 门锁业务流水号(仅实际操作门锁时返回) |
|
|||
|
|
| currentStatus | int | 重置后状态,固定 0 |
|
|||
|
|
| alreadyReset | boolean | 重置前是否已是 0(重复调用标识) |
|
|||
|
|
| accommodationKept | boolean | 是否保留了住宿分配 |
|
|||
|
|
| avatarCleared | boolean | 学员头像是否已清空 |
|
|||
|
|
| avatarSId | string | 被清空头像的学员标识 |
|
|||
|
|
|
|||
|
|
**分步失败场景(返回 code=500,`msg` 指明失败步骤)**
|
|||
|
|
|
|||
|
|
| 场景 | msg |
|
|||
|
|
|---|---|
|
|||
|
|
| 缺少 planId / studentId 参数 | Spring 参数缺失提示(`Required request parameter 'planId' ...`) |
|
|||
|
|
| planId 或 studentId 为空串 | `planId 和 studentId 不能为空` |
|
|||
|
|
| 报名记录不存在 | `未找到学员[{studentId}]在班级[{planId}]的参训记录` |
|
|||
|
|
| 学员已放弃培训(状态3) | `学员已放弃培训,不允许重置报到状态` |
|
|||
|
|
| 学员已结训(状态4) | `学员已结训,不允许重置报到状态` |
|
|||
|
|
| 步骤1 人脸解绑失败 | `步骤1 人脸解绑失败:{原因};参训状态未变更` |
|
|||
|
|
| 步骤2 门锁响应解析失败 | `步骤2 门锁授权清除响应解析失败:{原因};人脸已解绑,参训状态未变更` |
|
|||
|
|
| 步骤2 门锁清除失败 | `步骤2 门锁授权清除失败:{原因};人脸已解绑,参训状态未变更` |
|
|||
|
|
| 步骤3 状态复位失败 | `步骤3 参训状态重置失败;人脸与门锁授权已解除,请人工核对后重试` |
|
|||
|
|
| 学员档案缺失(前 3 步已完成) | `报到重置已完成,但未找到有效学员档案[{sId}],avatar 未清空`(失败响应中仍带 `data`) |
|
|||
|
|
| 清空头像异常(前 3 步已完成) | `报到重置已完成,但清空学员头像失败:{原因}`(失败响应中仍带 `data`) |
|
|||
|
|
|
|||
|
|
> 该接口为**非幂等敏感操作**,重复调用会对已复位的数据再次执行解绑/清库动作,建议设备端加二次确认。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 附录
|
|||
|
|
|
|||
|
|
### 10.1 枚举值速查
|
|||
|
|
|
|||
|
|
| 字段 | 取值 |
|
|||
|
|
|---|---|
|
|||
|
|
| 参训/报到状态 `enrollmentStatus` | 0 待报到、1 已报到、2 请假、3 放弃、4 已完成 |
|
|||
|
|
| 场地类型 `venueType` | 1 普通教室、2 实训场地 |
|
|||
|
|
| 课程类型 `courseType`(`train_course.c_type`) | 1 理论、2 实训 |
|
|||
|
|
| 账号关联状态 `accountBindingStatus` | 0 未关联、1 已关联 |
|
|||
|
|
| 人脸同步状态 `faceSync` | success / failed / skipped |
|
|||
|
|
| 房间占用 `accommodation` | 字符串 `已分配数/总床位数`,如 `2/4` |
|
|||
|
|
|
|||
|
|
### 10.2 关联数据表
|
|||
|
|
|
|||
|
|
| 模块 | 主要数据表 |
|
|||
|
|
|---|---|
|
|||
|
|
| 学员 | `train_student`、`train_enrollment` |
|
|||
|
|
| 教师 | `train_teacher` |
|
|||
|
|
| 开班 / 课程 | `train_class_plan`、`train_plan_course`、`train_course` |
|
|||
|
|
| 排课 | `train_lesson`、`train_classroom_info`、`train_training_site`、`train_electronic_board` |
|
|||
|
|
| 宿舍 | `train_dormitory_info`、`train_accommodation` |
|
|||
|
|
| 报到 | `train_class_report` |
|
|||
|
|
| 人脸/门锁 | 人脸识别服务、`/openapi/iot/stay/checkin` 门禁开放接口 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*文档结束。接口变更请同步更新本文件,并在提交说明中标注版本。*
|