Files
railwaysystem/RuoYi-Vue/doc/报到机接口API文档_20261105.md
T

28 KiB
Raw Blame History

报到机接口 API 文档

项目 内容
控制器 com.ruoyi.web.controller.api.TrainRegisterApiController
源文件 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TrainRegisterApiController.java
BasePath /api/register/v1
接口数量 12(8 个 GET + 4 个 POST)
鉴权 Spring Security 已放行 /api/register/v1/**(permitAll);仅 /report/reset 内部取登录用户,需携带 RuoYi Bearer Token
统一响应 AjaxResult(code / msg / data)
日期格式 yyyy-MM-dd HH:mm:ss(spring.jackson.date-format,时区 GMT+8)
文档更新 2026-11-09(新增宿舍布局接口)
编写依据 控制器源码逐行核对,与当前实现一致

目录


1. 通用约定

1.1 鉴权说明

  • 源代码类注释声明“其余接口复用 RuoYi Bearer 鉴权”,但当前 SecurityConfig 中已配置:
                .requestMatchers("/api/register/v1/**").permitAll();

即 整个 /api/register/v1/** 路径实际为匿名可访问,查询类与人脸上传接口不强制 Token。

  • 例外:POST /report/reset 内部通过 SecurityUtils.getUsername() 写入操作人,无登录态时该方法会抛 ServiceException("获取用户账户异常", 401)。因此该接口必须携带 Authorization: Bearer {token}。
  • 控制器注释提到的 X-Signature / X-Nonce(HMAC)验签目前未在本控制器内实现,DeviceHmacFilter 仅对 /api/iot/v1/device/login 生效。

1.2 统一响应结构

所有接口返回 AjaxResult:

{ "code": 200, "msg": "操作成功", "data": {} }
字段 类型 说明
code number 业务状态码,见 1.3
msg string 提示信息;成功时通常为 操作成功
data object / array 业务数据,无数据时该字段不出现

1.3 状态码与错误提示

code 含义 触发来源
200 成功 正常返回
401 未认证 / 无登录上下文 SecurityUtils 抛出的 ServiceException
500 参数缺失、图片解析失败、目标记录不存在等业务失败 控制器内 AjaxResult.error(...)

除框架级 401/404 外,业务失败统一为 code=500,调用方需读取 msg 区分原因。

1.4 公共数据结构

StudentItemVO(学员列表项,/student/list)

字段 类型 说明
sId string 学员ID(业务主键)
sName string 学员姓名
personNo string 人员编号
sGender string 性别
sBirth string 出生日期,yyyy-MM-dd
deptName string 所属部门名称
cardNo string 卡号
sPhone string 手机号
sEmail string 邮箱
idCardMasked string 证件号掩码
idCardLast4 string 证件号后 4 位
sourceType number 数据来源类型
status number 状态
avatar string 头像访问路径(如 /profile/upload/...png)
dutyLevel number 职务级别
extractStatus / extractTime / extractMsg string / string / string 人脸特征提取状态、时间、描述
photoMd5 string 人脸照片 MD5
featureData / featureMd5 / featureAlgoVersion / featureSize string / string / string / number 人脸特征数据及元信息
id number 主键
deptId number 部门ID
enrollmentStatus number 报到状态:0 待报到、1 已报到、2 请假、3 放弃、4 已完成
joinTime string 报到/入学时间

门锁入住结果 lockCheckin(LockStayCheckinResult)

字段 类型 说明
success boolean 是否成功
status string 处理状态
bizNo string 门锁业务流水号
httpStatus number 下游 HTTP 状态
code string 下游业务码
message string 下游提示信息
rawBody string 下游原始响应体

2. 接口总览

序号 分组 方法 路径 功能说明
1 学员信息 GET /api/register/v1/student/list 获取全部学员列表(含报到状态)
2 学员信息 GET /api/register/v1/student/{sId} 获取单个学员详情(含账号绑定信息)
3 学员信息 GET /api/register/v1/student/{sId}/base 获取学员基础信息(个人信息/开班/宿舍/教室/实训场地)
4 学员信息 GET /api/register/v1/student/{sId}/resources 获取学员关联资源(基础信息 + 课程 + 课表)
5 教师信息 GET /api/register/v1/teacher/list 获取全部教师列表(结构同学员列表)
6 教师信息 GET /api/register/v1/teacher/{tId}/base 获取教师基础信息(个人信息/宿舍/授课课表)
7 班级名单 GET /api/register/v1/class/student 获取进行中班级及其未报到学员名单
8 人脸照片 POST /api/register/v1/student/face 上传学员人脸照片并同步人脸设备、办理报到
9 人脸照片 POST /api/register/v1/teacher/face 上传教师人脸照片并同步人脸设备
10 人脸照片 POST /api/register/v1/face 按 employeeId 后缀统一分发到学员/教师上传
11 报到业务 POST /api/register/v1/report/reset 报到重置(解绑人脸、清门锁授权、状态回退)
12 宿舍布局 GET /api/register/v1/dormitory/layout 按楼栋/楼层/房间返回宿舍布局及已分配床位数

3. 学员信息

3.1 获取学员信息列表

  • 接口路径:/api/register/v1/student/list
  • 请求方法:GET
  • 功能说明:读取学员主档列表(train_student),并按 sId 反查 train_enrollment 报名记录,用第一条记录的报到状态与报到时间补齐 enrollmentStatus、joinTime。

请求参数:无(无分页、无过滤条件,返回全量)

返回结果说明:

  • data:StudentItemVO 数组,字段见 1.4。
  • 学员无报名记录时,enrollmentStatus 与 joinTime 为 null。
{
  "code": 200,
  "msg": "操作成功",
  "data": [
    {
      "sId": "S0001",
      "sName": "张三",
      "personNo": "P1001",
      "sGender": "1",
      "sBirth": "2000-01-01",
      "deptName": "供电段",
      "sPhone": "13800000000",
      "status": 1,
      "avatar": "/profile/upload/2026/11/05/xxxx.png",
      "enrollmentStatus": 1,
      "joinTime": "2026-11-05 09:12:33"
    }
  ]
}

3.2 获取学员详情

  • 接口路径:/api/register/v1/student/{sId}
  • 请求方法:GET
  • 功能说明:按学员ID查询详情,并在基础字段上补充账号绑定信息(userId、userName、nickName、accountBindingStatus)。

请求参数

名称 位置 类型 必填 说明
sId path string 是 学员ID,如 S0001

返回结果说明:

  • data 为 StudentAdminVO,继承 StudentDetailVO ← StudentItemVO。
  • 在 1.4 StudentItemVO 字段基础上,追加:
字段 类型 说明
faceRef string 人脸引用
remark string 备注
createBy / createTime string / string 创建人 / 创建时间
userId number 绑定的系统用户ID
userName string 登录账号
nickName string 用户昵称
accountBindingStatus number 账号绑定状态:1 已绑定,0 未绑定
  • 学员不存在时返回 {"code":200,"msg":"操作成功","data":null}。

3.3 获取学员基础信息

  • 接口路径:/api/register/v1/student/{sId}/base
  • 请求方法:GET
  • 功能说明:按 sId 聚合该学员的个人信息、所属开班计划、宿舍、教室、实训场地,供报到机首屏展示。开班 planId 取值优先取最新报到记录,缺失时从报名关系兜底。

请求参数

名称 位置 类型 必填 说明
sId path string 是 学员ID

返回结果说明:data 为对象(字段可能为 null):

字段 类型 说明
studInfo object 学员基础信息:sId、sName、sPhone、sGender、deptName、personNo
classPlan object 开班信息:planId、planName、startTime、endTime
dormitory object 宿舍信息:dormId、bedNo、dormBuilding、dormRoom
classroom object 教室信息(取自本计划首个带教室的课次):classRoomId、roomLocation、roomName
trainingSite object 实训场地信息(取自本计划首个带场地的课次):siteId、siteLocation、siteName、major
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "studInfo": { "sId": "S0001", "sName": "张三", "sPhone": "13800000000", "sGender": "1", "deptName": "供电段", "personNo": "P1001" },
    "classPlan": { "planId": "P2026001", "planName": "2026年第一期", "startTime": "2026-11-01 08:00:00", "endTime": "2026-11-30 18:00:00" },
    "dormitory": { "dormId": "D01", "bedNo": "3", "dormBuilding": "1号楼", "dormRoom": "101" },
    "classroom": { "classRoomId": "R01", "roomLocation": "教学楼2层", "roomName": "201" },
    "trainingSite": { "siteId": "T01", "siteLocation": "实训楼1层", "siteName": "接触网实训场", "major": "接触网" }
  }
}

注意:本接口不返回 courses 与 lesson(源码中已注释),需要课表请使用 3.4。


3.4 获取学员关联资源

  • 接口路径:/api/register/v1/student/{sId}/resources
  • 请求方法:GET
  • 功能说明:在 3.3 的基础上额外返回本计划课程列表与课次(含课程名),供报到机展示课表。

请求参数

名称 位置 类型 必填 说明
sId path string 是 学员ID

返回结果说明:data 在 3.3 全部字段之外,追加:

字段 类型 说明
courses array 本计划课程:cId(计划课程主键)、cName(课程名称)
lesson array 课次列表:startTime、endTime、planCourseId、cName
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "studInfo": { "sId": "S0001", "sName": "张三" },
    "classPlan": { "planId": "P2026001", "planName": "2026年第一期" },
    "courses": [ { "cId": 1001, "cName": "接触网巡视" } ],
    "lesson": [ { "startTime": "2026-11-06 08:00:00", "endTime": "2026-11-06 10:00:00", "planCourseId": 1001, "cName": "接触网巡视" } ],
    "dormitory": { "dormId": "D01", "bedNo": "3" },
    "classroom": { "classRoomId": "R01", "roomName": "201" },
    "trainingSite": { "siteId": "T01", "siteName": "接触网实训场" }
  }
}

4. 教师信息

4.1 获取教师信息列表

  • 接口路径:/api/register/v1/teacher/list
  • 请求方法:GET
  • 功能说明:读取教师主档(train_teacher),按与学员列表完全一致的结构返回,便于报到机统一处理。转换规则:
    • sId = tId + "_teacher"(与人脸库教师 employee_id 口径一致)
    • sName = tName,其余字段一一映射
    • 教师无报名记录,enrollmentStatus、joinTime 恒为 null

请求参数:无

返回结果说明:data 为 StudentItemVO 数组,实际填充字段:sId、sName、personNo、sGender、sBirth、deptName、cardNo、sPhone、sEmail、status、avatar、id。

{
  "code": 200,
  "msg": "操作成功",
  "data": [
    {
      "sId": "T0001_teacher",
      "sName": "李老师",
      "personNo": "P2001",
      "sGender": "1",
      "sPhone": "13900000000",
      "deptName": "供电段",
      "status": 1,
      "avatar": null,
      "enrollmentStatus": null,
      "joinTime": null
    }
  ]
}

4.2 获取教师基础信息

  • 接口路径:/api/register/v1/teacher/{tId}/base
  • 请求方法:GET
  • 功能说明:按教师工号聚合个人信息、宿舍信息与授课课表。兼容传入 tId + "_teacher" 口径:路径参数以 _teacher 结尾时会自动去除后缀再查询。

请求参数

名称 位置 类型 必填 说明
tId path string 是 教师工号;可传 T0001 或 T0001_teacher

返回结果说明:

字段 类型 说明
teacherInfo object 教师信息:tId、tName、tPhone、tGender、deptName、personNo、avatar;教师不存在时为 null
dormitory object dormId、bedNo、dormBuilding、dormRoom(无有效住宿时 dormId 为 null)
lesson array 授课课次(按开始时间升序,不传日期范围即全部);字段:lessonId、planCourseId、courseName、tId、teacherName、startTime、endTime、venueType、classRoomId、classRoomName、siteId、siteName、venueName、boardSn、remark
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "teacherInfo": { "tId": "T0001", "tName": "李老师", "tPhone": "13900000000", "tGender": "1", "deptName": "供电段", "personNo": "P2001", "avatar": null },
    "dormitory": { "dormId": "D02", "bedNo": "1", "dormBuilding": "2号楼", "dormRoom": "205" },
    "lesson": [
      { "lessonId": 9001, "courseName": "接触网巡视", "tId": "T0001", "teacherName": "李老师", "startTime": "2026-11-06 08:00:00", "endTime": "2026-11-06 10:00:00", "classRoomId": "R01", "classRoomName": "201", "venueName": "教学楼201" }
    ]
  }
}

5. 班级名单

5.1 获取进行中班级的学员名单

  • 接口路径:/api/register/v1/class/student
  • 请求方法:GET
  • 功能说明:查询所有进行中(planStatus = 1)的开班计划,并按计划取报名记录中未报到(enrollmentStatus = 0)的学员,学员列表作为班级属性 students 一并返回。单个学员主档缺失时用报名记录的冗余字段兜底,不会中断整体返回。

请求参数:无

返回结果说明:data 为班级数组:

字段 类型 说明
planId string 开班计划ID
planName string 开班计划名称
classId string 班级ID
className string 班级名称
students array 未报到学员:sId、sName、deptId、deptName
{
  "code": 200,
  "msg": "操作成功",
  "data": [
    {
      "planId": "P2026001",
      "planName": "2026年第一期",
      "classId": "C01",
      "className": "接触网一班",
      "students": [
        { "sId": "S0001", "sName": "张三", "deptId": 103, "deptName": "供电段" }
      ]
    }
  ]
}

6. 人脸照片上传

三个接口均为 POST + application/json,faceImage 支持纯 base64 或 data URI(data:image/png;base64,....)两种形式;服务端统一解码并转码为 PNG 落盘,路径形如 /profile/upload/yyyy/MM/dd/{uuid}.png,随后写回对应主档的 avatar 字段。

6.1 上传学员人脸照片

  • 接口路径:/api/register/v1/student/face
  • 请求方法:POST
  • 功能说明:保存学员人脸照片到 train_student.avatar,同步人脸识别设备(employee_id = sId),并按住宿记录办理报到:
    1. 更新报名记录 enrollmentStatus = 1、joinTime = 当前时间(存在报名记录时);
    2. 若学员有有效住宿记录(按 create_time 降序首条且 dormId 非空),生成门锁业务流水号并调用入住接口 /openapi/iot/stay/checkin。

请求参数(JSON Body)

名称 类型 必填 说明
sId string 是 学员ID
faceImage string 是 人脸图片 base64,可带 data:image/xxx;base64, 前缀

返回结果说明:data 字段:

字段 类型 说明
sId string 学员ID
avatar string 头像访问路径
faceSync string 设备同步状态:success / failed / skipped
faceMsg string 同步失败原因(仅失败时存在)
faceData any 设备返回的非 Map 数据(成功时可能追加)
lockCheckin object 门锁入住结果,结构见 1.4 lockCheckin(有住宿时返回)
lockAuthId string 门锁授权ID,当前固定为空串(有住宿时返回)
joinTime string 报到时间(有住宿时返回)

失败场景(code=500):

msg 触发条件
参数缺失:sId 与 faceImage 均为必填 任一参数为 null
sId 不能为空 sId 为空串
图片解析失败:... base64 非法 / 非图片 / 无法编码为 PNG
创建存储目录失败 落盘目录创建失败
图片写入失败:... 文件写入 IO 异常
学员不存在或更新失败 更新 train_student 影响行数为 0

人脸设备同步失败不影响接口成功返回,仅通过 faceSync=failed + faceMsg 体现。


6.2 上传教师人脸照片

  • 接口路径:/api/register/v1/teacher/face
  • 请求方法:POST
  • 功能说明:保存教师人脸照片到 train_teacher.avatar,以 employee_id = tId + "_teacher" 同步人脸识别设备。教师无报名记录,不处理报到状态;若教师已有有效住宿且已生成门锁流水号,则补发一次入住授权(有效期 15 天)。

请求参数(JSON Body)

名称 类型 必填 说明
teacherId string 是 教师工号(train_teacher.t_id),不含 _teacher 后缀
faceImage string 是 人脸图片 base64,可带 data URI 前缀

返回结果说明:data 字段:

字段 类型 说明
tId string 教师工号
avatar string 头像访问路径
faceSync string 设备同步状态:success / failed / skipped
faceMsg string 同步失败原因(仅失败时存在)
lockCheckin object 补发入住授权结果(教师有住宿且已生成 lockApiBizNo 时返回)
lockAuthId string 当前固定为空串(补发授权时返回)

失败场景(code=500):

msg 触发条件
参数缺失:teacherId 与 faceImage 均为必填 任一参数为 null
teacherId 不能为空 teacherId 为空串
图片解析失败:... / 创建存储目录失败 / 图片写入失败:... 同 6.1
教师不存在或更新失败 更新 train_teacher 影响行数为 0

6.3 上传人脸照片(统一入口)

  • 接口路径:/api/register/v1/face
  • 请求方法:POST
  • 功能说明:按 employeeId 后缀分发到 6.1 / 6.2,返回被调用方法的原样结果:
    • employeeId 以 _teacher 结尾 → 去掉后缀作为 teacherId,转 6.2;
    • 其他情况 → employeeId 即 sId,转 6.1。
  • 后缀匹配区分大小写且不做 trim(_TEACHER 会被当作学员ID)。

请求参数(JSON Body)

名称 类型 必填 说明
employeeId string 是 人脸库人员ID:学员 sId 或教师 tId + "_teacher"
faceImage string 是 人脸图片 base64,可带 data URI 前缀

返回结果说明:与分发目标接口完全一致(见 6.1 / 6.2 的 data 说明)。

失败场景(code=500):

msg 触发条件
参数缺失:employeeId 与 faceImage 均为必填 任一参数为 null
employeeId 不能为空 employeeId 为空串
employeeId 非法:教师工号(tId)不能为空 employeeId 仅由 _teacher 组成

7. 报到业务

7.1 报到重置

  • 接口路径:/api/register/v1/report/reset
  • 请求方法:POST
  • 功能说明:用于“误点他人信息导致人脸错绑”的补救。按顺序执行 4 步,任一关键步骤失败即中止并返回原因:
    1. 解绑人脸(复用 TrainFaceApiController.deleteEmployee,employee_id = studentId);
    2. 清除门锁入住授权(复用 TrainLockApiController.checkout),住宿分配记录保留;
    3. 参训状态重置为未报到 0(备注保持不变);
    4. 清空学员头像(train_student.avatar 置 NULL)。

请求参数(Query / Form,@RequestParam,非 JSON Body)

名称 类型 必填 说明
planId string 是 开班计划ID(train_enrollment.plan_id)
studentId string 是 学员ID(train_enrollment.student_id)

返回结果说明:data 字段:

字段 类型 说明
planId string 开班计划ID
studentId string 学员ID
enrollmentId number 参训记录主键
previousStatus number 重置前的报到状态
faceUnbind string 人脸解绑结果,成功为 success
lockCheckout string 门锁授权清除结果:success / skipped: 无有效住宿记录 / skipped: 缺少门锁业务流水号与宿舍信息
lockApiBizNo string 门锁业务流水号(清除成功时返回)
currentStatus number 重置后状态,固定 0
alreadyReset boolean 重置前是否已是未报到
accommodationKept boolean 是否保留了住宿记录
avatarCleared boolean 头像是否已清空(成功路径)
avatarSId string 清空头像的学员ID(成功路径)

失败场景(code=500):

msg 触发条件
planId 和 studentId 不能为空 任一参数为空
未找到学员[xxx]在班级[yyy]的参训记录 报名记录不存在
学员已放弃培训,不允许重置报到状态 previousStatus = 3
学员已结训,不允许重置报到状态 previousStatus = 4
步骤1 人脸解绑失败:...;参训状态未变更 人脸解绑未返回 200
步骤2 门锁授权清除响应解析失败:...;人脸已解绑,参训状态未变更 下游响应非法 JSON
步骤2 门锁授权清除失败:...;人脸已解绑,参训状态未变更 下游返回非 200
步骤3 参训状态重置失败;人脸与门锁授权已解除,请人工核对后重试 状态更新影响行数为 0
报到重置已完成,但未找到有效学员档案[xxx],avatar 未清空 主档缺失(data 仍返回已完成信息)
报到重置已完成,但清空学员头像失败:... 头像更新异常(data 仍返回已完成信息)
{
  "code": 200,
  "msg": "报到重置成功",
  "data": {
    "planId": "P2026001",
    "studentId": "S0001",
    "enrollmentId": 5001,
    "previousStatus": 1,
    "faceUnbind": "success",
    "lockCheckout": "success",
    "lockApiBizNo": "STAY20261105001",
    "currentStatus": 0,
    "alreadyReset": false,
    "accommodationKept": true,
    "avatarCleared": true,
    "avatarSId": "S0001"
  }
}

8. 宿舍布局

8.1 获取宿舍布局信息

  • 接口路径:/api/register/v1/dormitory/layout
  • 请求方法:GET
  • 功能说明:查询 train_dormitory_info(仅未删除房间),依次按 dorm_building(楼栋)→ dorm_floor(楼层)→ dorm_room(房间号)分组;并左关联 train_accommodation 统计每个房间的已分配床位数(住宿状态 0 预分配 / 1 已入住 计入,2 已退宿 不计),总床位数取房间核定容量 capacity。

请求参数:无

返回结果说明:

  • data 为三层嵌套对象,键依次为「楼栋名称 → 楼层 → 房间号」,每间房的值包含:
字段 类型 说明
id number 宿舍自增编号(train_dormitory_info.id)
dorm_room string 房间号
accommodation string 已分配床位数/总床位数,如 "2/4"
  • 楼栋、楼层、房间均按数据库升序排列(dorm_building, dorm_floor, dorm_room),嵌套对象使用有序 Map 输出,顺序稳定。
  • 无房间数据时 data 为空对象 {}。
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "1号楼": {
      "1": {
        "101": { "id": 1, "dorm_room": "101", "accommodation": "2/4" },
        "102": { "id": 2, "dorm_room": "102", "accommodation": "0/4" }
      },
      "2": {
        "201": { "id": 5, "dorm_room": "201", "accommodation": "4/6" }
      }
    },
    "2号楼": {
      "1": {
        "101": { "id": 9, "dorm_room": "101", "accommodation": "1/2" }
      }
    }
  }
}

说明:同一楼栋内房间号唯一(约束 uq_dorm_building_room),因此以房间号作为楼层下的键不会冲突;楼层为空时键为 未标注楼层。


9. 附录

9.1 典型调用流程

  1. GET /student/list 或 GET /class/student —— 报到机展示待报到人员。
  2. GET /teacher/list —— 展示教师名单(sId 形如 T0001_teacher)。
  3. 人员点击后:GET /student/{sId}/resources(或 /base)—— 展示开班、宿舍、教室、课表。
  4. 采集人脸后:POST /face(统一入口,传 employeeId + faceImage)—— 完成照片入库、设备下发、报到登记、门锁入住。
  5. 宿舍看板:GET /dormitory/layout —— 按楼栋/楼层/房间展示床位占用情况。
  6. 误绑时:POST /report/reset?planId=...&studentId=... —— 回退报到与人脸/门锁授权。

9.2 调用示例

# 学员列表
curl "http://localhost:8096/api/register/v1/student/list"

# 学员关联资源
curl "http://localhost:8096/api/register/v1/student/S0001/resources"

# 教师基础信息(tId 可带 _teacher 后缀)
curl "http://localhost:8096/api/register/v1/teacher/T0001_teacher/base"

# 统一人脸上传
curl -X POST "http://localhost:8096/api/register/v1/face" \
  -H "Content-Type: application/json" \
  -d '{"employeeId":"S0001","faceImage":"data:image/jpeg;base64,/9j/4AAQSkZJRg..."}'

# 报到重置(需登录态)
curl -X POST "http://localhost:8096/api/register/v1/report/reset?planId=P2026001&studentId=S0001" \
  -H "Authorization: Bearer {token}"

# 宿舍布局
curl "http://localhost:8096/api/register/v1/dormitory/layout"

9.3 与源码注释的差异说明

位置 注释/声明 实际实现
类注释 登录接口需 HMAC 签名(X-Signature/X-Nonce) 控制器内未实现;DeviceHmacFilter 仅覆盖 /api/iot/v1/device/login
SecurityConfig 注释 /api/register/v1/** 走 Bearer 鉴权 已配置 permitAll,除 /report/reset 外不校验 Token
/student/{sId}/base 注释称返回“课表、实训场地” 实际不返回 courses、lesson,需调用 /student/{sId}/resources