# 功能房预约(门户)API 文档(v2) 更新时间:2025-11-07 ## 概览 - 架构:门户只读/自助(/portal/facility),管理端在 `/manage`(见管理文档)。 - 业务:按“楼房→房间”浏览;查看时间轴;提交预约;我的预约自助修改/取消;进行中提前结束;查看详情。 - 角色:登录用户(user)。 ## 约定与通用 - 鉴权:统一请求头 `Authorization: Bearer `。 - 基础路径:门户 `/portal/facility`。 - 分页:`pageNum`(默1),`pageSize`(默10);返回 `{ rows, total }`。 - 时间:`yyyy-MM-dd HH:mm:ss`。 - 响应包: - 成功:`{ code:200, msg:'操作成功', data: {...} }` 或 `{ code:200, rows:[...], total:n }` - 失败:`{ code:4xx/5xx, msg:'错误说明' }` - 常见错误: - 400 参数错误/校验失败(时段冲突/时长非法/参与人数不足/用户无效/房间禁用/申请人被封禁等以 500+msg 表达) - 401 未登录;404 不存在;409 状态冲突(开始后修改/取消、非进行中提前结束);500 业务失败 ## 权限与鉴权 - 门户接口均需登录(`isAuthenticated()`);按钮级权限由管理端控制,门户不拦截。 ## 数据模型(Schema) - Building ```json { "id":1, "buildingName":"信息楼", "status":"0", "remark":"" } ``` - Room ```json { "id":2, "buildingId":1, "floorNo":2, "roomName":"会议室201", "capacity":20, "equipmentTags":"白板,电视", "status":"0" } ``` - Booking ```json { "id":10001, "roomId":2, "applicantId":1000, "purpose":"课程讨论会", "startTime":"2025-11-10 09:00:00", "endTime":"2025-11-10 12:00:00", "durationMinutes":180, "status":"0" } ``` - BookingUser(部分) ```json { "id":11, "bookingId":10001, "userId":1002, "isApplicant":"0" } ``` - TimelineSegment ```json { "id":10001, "start":"2025-11-10 09:00:00", "end":"2025-11-10 12:00:00", "status":"approved" } ``` ## 业务规则(关键) - 创建/修改:开始时间>当前;结束>开始;`durationMinutes` 不超过设置(默认4320);与同房间 `pending|approved|ongoing` 不重叠;使用人去重后≥3(含申请人,且均为有效用户)。 - 审核开关:`auditRequired=true` → 新建为 `pending(0)`;否则直接 `approved(1)`。 - 被驳回后修改:允许编辑并重新提交;根据开关进入 `pending(0)` 或 `approved(1)`,同时清空 `rejectReason`。 - 取消:仅申请人、仅 `pending/approved` 且开始前;释放时间段。 - 提前结束:仅申请人,且“已批准或进行中(需实际已开始)”允许;新 `endTime` ≥ 当前 且 > `startTime`;若新结束时间不晚于当前,状态变为 `completed(5)`。 - 时间轴:半开区间 [start,end);仅返回 `pending|approved|ongoing|completed` 段。 ## 路由清单 ### 楼房列表 - 方法:GET | 路径:/portal/facility/building/list | 权限:登录 - 请求参数(query,可选): - keyword(string) 按楼房名模糊 - pageNum(int) 默1;pageSize(int) 默10 - 返回:`{ code:200, rows:[Building], total:n }` ### 房间列表(仅启用) - 方法:GET | 路径:/portal/facility/room/list | 权限:登录 - 请求参数(query,必填): - buildingId(long) | floorNo(int) - pageNum/pageSize(分页) - 返回:`{ code:200, rows:[Room], total:n }` ### 房间详情 - 方法:GET | 路径:/portal/facility/room/{id} | 权限:登录 - 返回:`{ code:200, data: Room }` ### 时间轴 - 方法:GET | 路径:/portal/facility/room/{id}/timeline | 权限:登录 - 请求参数(query,可选):from(datetime) | to(datetime) - 返回示例: ```json { "code": 200, "data": { "roomId": 2, "range": { "from": "2025-11-01 00:00:00", "to": "2025-12-01 00:00:00" }, "segments": [ { "id": 10001, "start": "2025-11-10 09:00:00", "end": "2025-11-10 12:00:00", "status": "approved" } ] } } ``` ### 创建预约 - 方法:POST | 路径:/portal/facility/booking | 权限:登录 - 请求体(json): ```json { "roomId": 2, "purpose": "课程讨论会", "startTime": "2025-11-10 09:00:00", "endTime": "2025-11-10 12:00:00", "userIdList": [1001,1002,1003] } ``` - 成功:`{ code:200 }` - 失败常见:`{ code:500, msg:"时间段冲突/被封禁/房间禁用/时长非法/参与人不足或无效" }` ### 我的预约列表 - 方法:GET | 路径:/portal/facility/booking/my/list | 权限:登录 - 请求参数(query,可选):status(string) 0|1|2|3|4|5;pageNum/pageSize - 返回:`{ code:200, rows:[Booking], total }`(服务端补 `roomName`) ### 修改预约(开始前) - 方法:PUT | 路径:/portal/facility/booking/{id} | 权限:登录 - 请求体(json,可选字段): ```json { "purpose":"更新主题", "startTime":"2025-11-10 10:00:00", "endTime":"2025-11-10 12:00:00", "userIdList":[1001,1002,1004] } ``` - 返回:`{ code:200 }`(触发与创建相同校验) - 备注:仅申请人、仅 `pending/approved/rejected` 且开始前;若当前状态为 `rejected(2)`,编辑后根据审核开关进入 `pending(0)` 或 `approved(1)`。 ### 进行中提前结束 - 方法:PUT | 路径:/portal/facility/booking/{id}/end-early | 权限:登录 - 请求体:`{ "endTime":"2025-11-10 11:00:00" }` - 返回:`{ code:200 }` - 备注:已批准或进行中均可调用(需实际已开始);若传入结束时间早于当前,系统将取当前时间;当新的结束时间不晚于当前,状态置为 `completed(5)`。 ### 取消预约(开始前) - 方法:DELETE | 路径:/portal/facility/booking/{id} | 权限:登录 - 返回:`{ code:200 }` - 备注:仅申请人可取消;仅 `pending/approved` 且开始前。 ### 预约详情 - 方法:GET | 路径:/portal/facility/booking/{id} | 权限:登录 - 返回:`{ code:200, data: { booking:{...}, users:[...], meta:{ roomName, buildingName, applicantName, statusText } } }` ## 备注 - 冲突判定采用半开区间 [start,end);取消/驳回不进入时间轴,但会释放区间。 - 审核开关与时长上限来自 `/manage/facility/setting/audit-required`。 - 如需房间搜索与排序,遵循通用分页 `orderByColumn/isAsc` 扩展策略(后端按需启用)。 ## Apifox 指南(门户) - 环境:`baseURL=http://localhost:8080`,Header:`Authorization: Bearer {{token}}` - 用例串: 1) 楼房/房间列表 → 时间轴 → 创建预约 2) 我的预约:修改时间/参与人 → 校验冲突提示 → 成功后详情校验 users/meta 3) 进行中提前结束 → 断言 `endTime` 收缩 4) 取消预约(开始前) → 时间轴段释放