Files
railwaysystem/RuoYi-Vue/doc/电子班牌接口API文档.md
T

24 KiB
Raw Blame History

电子班牌接口 API 文档

项目 内容
控制器 com.ruoyi.web.controller.api.TrainBoardApiController
源文件 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TrainBoardApiController.java
BasePath /api/board/v1
接口数量 7(4 个查询类 + 1 个签到上报 + 2 个新增能力)
鉴权 RuoYi Bearer Token(Authorization: Bearer {token})
文档更新 2026-11-03
编写依据 控制器源码逐行核对,与当前实现一致

目录


1. 通用约定

1.1 鉴权

  • 所有接口均需携带 Authorization: Bearer {token},Token 由平台登录接口签发。
  • 未携带或 Token 失效时,返回 HTTP 200 + 响应体 code=401:
{ "code": 401, "msg": "请求访问:/api/board/v1/signageService/selectClassroom,认证失败,无法访问系统资源" }

本控制器未使用 @PreAuthorize 数据权限注解,因此不存在 403 业务场景。

1.2 统一响应结构

所有接口返回 AjaxResult:

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

1.3 状态码

code 含义 HTTP 状态 触发来源
200 成功 200 正常返回
401 未认证 / Token 无效 200 AuthenticationEntryPointImpl
404 接口路径不存在 404 NoResourceFoundException
500 参数缺失、参数格式错误、数据校验失败、控制器内业务拦截、系统异常 200 GlobalExceptionHandler / 控制器返回值
40080 / 40081 / 40085 / 40086 / 40087 考勤业务码(计划不一致 / 课次不存在 / 未报到 / 已放弃 / 已结训) 200 ServiceException(AttendanceErrorCode)

调用方必须判断响应体 code:除 404 外,失败场景的 HTTP 状态码仍是 200。

1.4 列表数据包装

除 3.1 查询教室信息(data 直接是数组)外,其余查询接口的 data 为:

{ "total": 2, "rows": [ ... ] }
字段 类型 说明
total number 本次返回的记录数(非分页总数)
rows array 数据列表,无数据时为 []

1.5 字段类型说明

类注释约定 id / classId / classroomId / courseId / teacherId / stuId / studentId 为 Long, 但本系统相关表以业务编码为主键(字符串),因此这些字段返回字符串; 仅 lessonId(id)、enrollmentId、zoneId、seatId、capacity、classHour 等为数值。


2. 接口总览

# 接口名称 方法 路径 用途
3.1 查询教室信息 GET /api/board/v1/signageService/selectClassroom 返回全部教学教室与实训场地
3.2 查询指定教室当天课程 GET /api/board/v1/signageService/coursesInClassroom 按教室与日期范围返回排课
3.3 查询指定班级在指定教室的座位 GET /api/board/v1/signageService/studentInClassroom 返回座位网格(含学员姓名)
3.4 查询班级学员卡号 GET /api/board/v1/signageService/studentCard 刷卡校验用卡号与班级信息
3.5 上报签到数据 POST /api/board/v1/signageService/checkin/upload JSON 上报签到并落库
3.6 查询本节课签到记录 GET /api/board/v1/signageService/checkin/list 按课次返回签到流水与学员姓名
3.7 查询座位布局 GET /api/board/v1/signageService/seatLayout 仅读 train_class_seat 的座位布局

3. 接口详情

3.1 查询教室信息

用途:返回全部教学教室 + 实训场地(train_classroom_info UNION train_training_site),供班牌后台定位终端绑定教室。

项 内容
HTTP 方法 GET
请求路径 /api/board/v1/signageService/selectClassroom
鉴权 需要

请求参数:无。

请求体:无。

响应结构:data 为数组(不是 {total, rows} 包装)。

字段 类型 说明
id string 教室ID(class_room_id)或场地ID(site_id)
name string 教室/场地名称
campus string 校区/位置
capacity number 容量
outside number 0=教室,1=实训场地
category string 教室 / 实训场地

成功示例

{
  "code": 200,
  "msg": "操作成功",
  "data": [
    { "id": "CR01", "name": "多媒体教室01", "campus": "一号教学楼3层", "capacity": 60, "outside": 0, "category": "教室" },
    { "id": "SITE01", "name": "信号实训场", "campus": "实训楼1层", "capacity": 40, "outside": 1, "category": "实训场地" }
  ]
}

异常说明:未认证 → code=401;无数据 → data: []。


3.2 查询指定教室当天课程

用途:按教室/场地与日期范围(含首尾日期)返回排课列表。文档约定 beginDate=endDate=当天,接口本身不限制两者相等。

项 内容
HTTP 方法 GET
请求路径 /api/board/v1/signageService/coursesInClassroom
鉴权 需要

请求参数(Query String)

名称 类型 必填 默认值 说明
classroomId string 是 无 教室ID(class_room_id)或场地ID(site_id),SQL 同时匹配两列
beginDate string 是 无 开始日期 yyyy-MM-dd,条件 start_time >= beginDate
endDate string 是 无 结束日期 yyyy-MM-dd,条件 start_time < endDate + 1 天(含当天)

请求体:无。

响应结构:data = { total, rows[] }

字段 类型 说明
id number 排课ID(train_lesson.lesson_id),即 3.5 的 lessonId
courseId string 课程主数据ID(train_course.c_id)
classId string 班级ID(train_class_plan.plan_id)
classroomId string 教室ID或场地ID(COALESCE(class_room_id, site_id))
courseName string 课程名称
couresName string 兼容旧拼写的课程名称(与 courseName 同值)
courseTime string 上课时间 yyyy-MM-dd HH:mm:ss
classHour number 时长(分钟)
className string 班级名称
teacherId string 教师ID(train_lesson.t_id)
teacherName string 教师姓名,未排教师为 null
courseIntro string 课程简介(train_course.teaching_objective)
isPublic number 固定 0

成功示例

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "id": 1001, "courseId": "CR01", "classId": "PLAN_A", "classroomId": "CR01",
        "courseName": "电子班牌数字化实务", "couresName": "电子班牌数字化实务",
        "courseTime": "2026-11-02 09:00:00", "classHour": 90,
        "className": "2026年第一期培训班", "teacherId": "T101", "teacherName": "张三",
        "courseIntro": "班牌设备安装与配置", "isPublic": 0
      }
    ]
  }
}

异常说明

场景 响应
缺少 classroomId {"code":500,"msg":"Required request parameter 'classroomId' for method parameter type String is not present"}
无排课 {"code":200,"msg":"操作成功","data":{"total":0,"rows":[]}}

3.3 查询班级学员卡号

用途:按班级返回学员卡号与班级、住宿信息,用于班牌刷卡校验。仅返回参训状态非“已放弃(3)”的学员。

项 内容
HTTP 方法 GET
请求路径 /api/board/v1/signageService/studentCard
鉴权 需要

请求参数(Query String)

名称 类型 必填 默认值 说明
classId string 是 无 班级ID(train_enrollment.plan_id)

请求体:无。

响应结构:data = { total, rows[] }

字段 类型 说明
cardNo string 卡号(train_student.card_no,保留前导零)
studentId string 学员ID(s_id)
classId string 班级ID
studentName string 学员姓名
className string 班级名称
id number 参训档案ID(enrollment_id,不是学员ID)
roomId string 宿舍ID,未分配为 null
bedType string 床位类型(预留,固定 null)
seatNumber string 床位号,未分配为 null

成功示例

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "total": 1,
    "rows": [
      { "cardNo": "00012345", "studentId": "STU_1", "classId": "PLAN_A", "studentName": "王五", "className": "2026年第一期培训班", "id": 201, "roomId": "DORM-101", "bedType": null, "seatNumber": "1" }
    ]
  }
}

异常说明:缺少 classId → code=500;无数据 → {total:0, rows:[]}。


3.4 上报签到数据

用途:班牌上报学员签到。服务端按 studentId 在课次所属培训班内查询 train_enrollment 得到 enrollmentId,写入 train_student_checkin(student_id、board_id、lesson_id、sign_in_time 一并落库)。

项 内容
HTTP 方法 POST
请求路径 /api/board/v1/signageService/checkin/upload
鉴权 需要
Content-Type 必须 application/json
文件上传 无

请求参数:无 Query 参数,全部字段在请求体中。

请求体结构(BoardCheckinUploadRequest)

名称 类型 必填 默认值 说明
studentId string 是 无 学员ID(train_student.s_id),首尾空格会被去除
boardId string 否 null 门牌(班牌)ID,写入 train_student_checkin.board_id;空串按 null 处理
lessonId number(long) 是 无 课程(课次)ID,对应 train_student_checkin.lesson_id,取值来自 3.2 的 id
signInTime string 否 服务器当前时间 签到时间,格式 yyyy-MM-dd HH:mm:ss;格式非法直接报错,不静默改写
{
  "studentId": "STU_1",
  "boardId": "BP001",
  "lessonId": 1001,
  "signInTime": "2026-11-02 08:30:00"
}

响应结构(data 为单对象)

字段 类型 说明
checkinId number 考勤记录ID
studentId string 学员ID(库中 student_id,为空时回填请求值)
enrollmentId number 参训档案ID(由 studentId + 班次推导)
lessonId number 课次ID
boardId string 班牌ID,未传为 null
signInTime string 实际落库的签到时间 yyyy-MM-dd HH:mm:ss

成功示例

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "checkinId": 9001, "studentId": "STU_1", "enrollmentId": 201,
    "lessonId": 1001, "boardId": "BP001", "signInTime": "2026-11-02 08:30:00"
  }
}

异常与错误说明

场景 code 响应 msg
studentId 为空 500 studentId 不能为空
lessonId 为空 500 lessonId 不能为空
signInTime 格式错误 500 signInTime 格式不正确,应为 yyyy-MM-dd HH:mm:ss
课次不存在 500 课程(课次)不存在: 1001
课次未关联有效培训计划 500 课程(课次)[1001]未关联有效的培训计划
学员无该班参训记录 500 未找到学员[STU_1]在班级[PLAN_A]的参训记录
非 JSON / 空请求体 500 Spring 反序列化异常信息(如 Content-Type 'text/plain' is not supported)
未认证 401 请求访问:/api/board/v1/signageService/checkin/upload,认证失败,无法访问系统资源
学员未报到 / 已放弃 / 已结训 40085 / 40086 / 40087 对应中文提示(见 AttendanceErrorCode)
课次所属计划与参训计划不一致 40080 业务不变量校验失败:考勤学员与课次所属培训班不一致

业务规则

  1. 幂等:同一 enrollmentId + lessonId 已有签到记录(sign_in_time 非空)时返回已有记录,不覆盖首次签到时间。
  2. 生命周期:仅“已报到(1)”“请假(2)”状态允许签到。
  3. 计划一致性:学员参训档案所属培训班必须与课次所属培训班一致。
  4. 打卡方式:固定按设备打卡 checkinWay=1 落库。

3.5 查询本节课签到记录

用途:按 lessonId 返回 train_student_checkin 签到流水,并按 studentId 关联 train_student 返回学员姓名(s_name)。

项 内容
HTTP 方法 GET
请求路径 /api/board/v1/signageService/checkin/list
鉴权 需要

请求参数(Query String)

名称 类型 必填 默认值 说明
lessonId number(long) 是 无 课程(课次)ID;非数字时返回参数类型不匹配错误

请求体:无。

响应结构:data = { total, rows[] },rows[] 为 TrainStudentCheckin:

字段 类型 说明
checkinId number 考勤记录ID
enrollmentId number 参训档案ID
lessonId number 课次ID
studentId string 学员ID(优先取 train_student_checkin.student_id,为空取参训档案的 student_id)
studentName string 学员姓名(train_student.s_name)
planId string 培训班ID
planName string 培训班名称
className string 班级名称
courseName string 课程名称
boardId string 打卡班牌ID
boardSn string 班牌序列号
boardName string 班牌名称
checkinWay number 打卡方式:1 人脸/设备,2 刷卡,3 扫码,4 教师代签
signInTime string 签到时间 yyyy-MM-dd HH:mm:ss,未签到为 null
signOutTime string 签退时间 yyyy-MM-dd HH:mm:ss,未签退为 null
attendanceStatus number 考勤结论:0 缺勤,1 正常,2 迟到,3 早退,4 请假
manualFlag number 是否人工修正:0 否,1 是
createBy / createTime / updateBy / updateTime / remark string 审计字段(时间格式 yyyy-MM-dd HH:mm:ss)

params 为空时不输出;searchValue 始终不输出。

成功示例

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "checkinId": 9001, "enrollmentId": 201, "lessonId": 1001,
        "studentId": "STU_1", "studentName": "张三",
        "planId": "PLAN_A", "planName": "2026年第一期培训班", "className": "一班",
        "courseName": "电子班牌数字化实务",
        "boardId": "BP001", "boardSn": "BP001", "boardName": "1号班牌",
        "checkinWay": 1, "signInTime": "2026-11-02 08:30:00", "signOutTime": null,
        "attendanceStatus": 1, "manualFlag": 0,
        "createBy": "board_device", "createTime": "2026-11-02 08:30:01",
        "updateBy": null, "updateTime": null, "remark": null
      }
    ]
  }
}

异常与错误说明

场景 响应
缺少 lessonId {"code":500,"msg":"Required request parameter 'lessonId' for method parameter type Long is not present"}
lessonId 非数字 {"code":500,"msg":"请求参数类型不匹配,参数[lessonId]要求类型为:'java.lang.Long',但输入值为:'abc'"}
课次无签到记录 {"code":200,"msg":"操作成功","data":{"total":0,"rows":[]}}

3.6 查询座位布局

用途:按班级与教室查询座位布局,仅读取 train_class_seat 单表,不关联学员、教室、班级表;不校验班级是否删除、学员是否存在。

项 内容
HTTP 方法 GET
请求路径 /api/board/v1/signageService/seatLayout
鉴权 需要

请求参数(Query String)

名称 类型 必填 默认值 说明
planId string 是 无 班级ID,对应 train_class_seat.plan_id
classroomId string 是 无 教室ID,对应 train_class_seat.classroom_id

请求体:无。

响应结构:data = { total, rows[] }

字段 类型 说明
seatId number 座位主键(seat_id)
planId string 班级ID(plan_id)
classroomId string 教室ID(classroom_id)
rowIndex number 行号,从 1 开始
colIndex number 列号,从 1 开始
seatCode string 物理座位标识(seat_code)
canceled number 0=正常,1=取消位置(不做过滤,原样返回)
studentId string 占用座位学员ID,空座为 null
zoneId number 区域ID
deptDetail string 部门
job string 职务

排序:row_index, col_index 升序。

成功示例

http://localhost:8096/api/board/v1/signageService/seatLayout?classroomId=afcf21a8bd99488cb19638d285f157a8&planId=f70ec13a651942e8a704ee4cc010c95e

{
    "msg": "操作成功",
    "code": 200,
    "data": {
        "total": 2,
        "rows": [
            {
                "canceled": 0,
                "classroomId": "afcf21a8bd99488cb19638d285f157a8",
                "colIndex": 5,
                "deptDetail": null,
                "job": null,
                "planId": "f70ec13a651942e8a704ee4cc010c95e",
                "rowIndex": 2,
                "seatCode": "2-5",
                "seatId": 29,
                "studentId": "c78c425e66384104bf37d150519fc5d3",
                "zoneId": null
            },
            {
                "canceled": 0,
                "classroomId": "afcf21a8bd99488cb19638d285f157a8",
                "colIndex": 9,
                "deptDetail": null,
                "job": null,
                "planId": "f70ec13a651942e8a704ee4cc010c95e",
                "rowIndex": 3,
                "seatCode": "3-9",
                "seatId": 30,
                "studentId": "63d889e8be2c4d61900d09b51b2108a5",
                "zoneId": null
            }
        ]
    }
}

异常与错误说明

场景 响应
缺少 planId 或 classroomId code=500,msg 为 Spring 缺参提示
该班该教室无座位数据 {"code":200,"msg":"操作成功","data":{"total":0,"rows":[]}}
表 train_class_seat 不存在 code=500,msg 含 Table 'xxx.train_class_seat' doesn't exist(需先执行 sql/train/v2/019_signage.sql)

4. 异常与错误汇总

类型 返回形式 说明
未认证 HTTP 200,code=401 Token 缺失、过期、伪造
路径不存在 HTTP 404,code=404,msg=接口不存在或未启用 路由未匹配
缺少必填 Query 参数 HTTP 200,code=500 Required request parameter 'xxx' ... is not present
参数类型不匹配 HTTP 200,code=500 请求参数类型不匹配,参数[lessonId]要求类型为:'java.lang.Long',但输入值为:'abc'
请求方法不支持 HTTP 200,code=500 Request method 'GET' is not supported
请求体非 JSON HTTP 200,code=500 Content-Type 'xxx' is not supported
控制器内业务拦截 HTTP 200,code=500 见 3.5 异常表
考勤业务异常 HTTP 200,code=40080/40081/40085/40086/40087 AttendanceErrorCode

AttendanceErrorCode 常用码:

code 含义
40080 考勤学员与课次所属培训班不一致
40081 课次不存在
40085 学员尚未完成开班报到,禁止录入课次考勤
40086 学员已放弃培训
40087 学员已结训

5. 调用示例

# 登录获取 token(按平台实际登录接口调整)
TOKEN=$(curl -s -X POST 'http://192.168.106.24:8096/login' \
  -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"admin123"}' | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')

# 3.1 教室信息
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/selectClassroom' \
  -H "Authorization: Bearer $TOKEN"

# 3.2 指定教室当天课程
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/coursesInClassroom?classroomId=CR01&beginDate=2026-11-02&endDate=2026-11-02' \
  -H "Authorization: Bearer $TOKEN"

# 3.3 指定班级在指定教室的座位
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/studentInClassroom?classroomId=CR01&classId=PLAN_A' \
  -H "Authorization: Bearer $TOKEN"

# 3.4 班级学员卡号
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/studentCard?classId=PLAN_A' \
  -H "Authorization: Bearer $TOKEN"

# 3.5 上报签到(JSON 请求体)
curl -s -X POST 'http://192.168.106.24:8096/api/board/v1/signageService/checkin/upload' \
  -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \
  -d '{"studentId":"STU_1","boardId":"BP001","lessonId":1001,"signInTime":"2026-11-02 08:30:00"}'

# 3.6 本节课签到记录
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/checkin/list?lessonId=1001' \
  -H "Authorization: Bearer $TOKEN"

# 3.7 座位布局
curl -s 'http://192.168.106.24:8096/api/board/v1/signageService/seatLayout?planId=P2026001&classroomId=CR-001' \
  -H "Authorization: Bearer $TOKEN"

6. 附录

6.1 数据来源

接口 主要数据表
3.1 train_classroom_info、train_training_site
3.2 train_lesson、train_plan_course、train_course、train_class_plan、train_teacher
3.3 train_class_seat、train_class_plan、train_student
3.4 train_enrollment、train_student、train_class_plan、train_accommodation、train_dormitory_info
3.5 train_lesson、train_plan_course、train_enrollment、train_student_checkin
3.6 train_student_checkin、train_enrollment、train_student、train_class_plan、train_plan_course、train_course、train_electronic_board
3.7 train_class_seat(单表)

6.2 Swagger

Swagger UI:/swagger-ui/index.html,分组 电子班牌接口。 若 3.5 的 Request body 显示为 query 参数,说明部署的是旧包(当前实现为 @RequestBody)。

6.3 已知约束

  1. lessonId 是课次ID(train_lesson.lesson_id,数值),不是课程编码(c_id,如 CR01);班牌须先调用 3.2 获取 id。
  2. 3.5 只接受 JSON 请求体,query/form 写法无效。
  3. 3.5 依赖 train_student_checkin.student_id 列;报 Unknown column 'a.student_id' 时需执行 sql/train/v2/020b_add_checkin_student_id_mysql.sql(MySQL)或 sql/train/v2/020_add_checkin_student_id.sql(KingbaseES/PostgreSQL)。
  4. 3.3 与 3.7 的区别:3.3 关联 train_student 返回姓名并过滤已删除班级;3.7 严格单表返回,含 canceled=1 的座位,不做班级有效性校验。
  5. 所有查询接口的 total 为本次返回条数,不是分页总数。