# 酒店二维码模块开发文档 ## 1. 模块概述 **模块名称**: `forge-hotel` **包路径**: `com.mdframe.forge.business.core.hotel` **位置**: `forge-server/forge-business/forge-hotel/` ### 1.1 功能范围 | 功能 | 说明 | |------|------| | 二维码批量生成 | 批量生成不绑定房间的二维码,支持 10/50/100/200 个一批 | | 二维码绑定/重绑/解绑 | 员工通过 PC 后台扫码绑定房间,记录操作人和时间 | | 二维码状态管理 | 启用/禁用二维码(字典 sys_normal_disable: 0=启用, 1=禁用) | | 绑定日志追溯 | 完整记录每次绑定/重绑/解绑操作 | | 批量删除 | 勾选多个二维码批量逻辑删除,已绑定房间的拒绝删除 | | 批量下载ZIP | 勾选多个二维码生成 PNG 图片打包为 ZIP 下载 | | 单条下载 | 操作列下载单个二维码 PNG 图片 | | 房间管理 | 房间 CRUD,关联房型 | | 房型管理 | 房型 CRUD | | 扫码查询(开放接口) | 免登录接口,供顾客/钉钉H5/小程序调用 | ### 1.2 三端架构 ``` PC 管理后台(Sa-Token) → 批量生成、列表、批量删除、批量下载ZIP、单条下载、绑定/重绑/解绑、禁用/启用 钉钉 H5(DingTalk SSO) → 员工扫码绑定房间、重绑、查看绑定状态 微信/支付宝小程序 → 顾客扫码点餐(免登录,调用 /hotel/open/scan) ``` --- ## 2. 数据库设计 ### 2.1 表结构 #### hotel_room_type(房型表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键(雪花算法) | | tenant_id | BIGINT | 租户ID,默认1 | | type_name | VARCHAR(64) | 房型名称 | | description | VARCHAR(256) | 房型描述 | | sort_order | INT | 排序号 | | del_flag | BIGINT | 逻辑删除标记 | | create_by/create_time/create_dept | - | 审计字段 | | update_by/update_time | - | 审计字段 | #### hotel_room(房间表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | tenant_id | BIGINT | 租户ID | | room_no | VARCHAR(32) | 房间号(租户内唯一) | | room_type_id | BIGINT | 房型ID | | floor_no | VARCHAR(16) | 楼层 | | status | VARCHAR(16) | 状态:VACANT/OCCUPIED/CLEANING/MAINTENANCE | | sort_order | INT | 排序号 | | remark | VARCHAR(256) | 备注 | | del_flag | BIGINT | 逻辑删除标记 | **唯一索引**: `UNIQUE (tenant_id, room_no, del_flag)` #### hotel_qr_code(二维码表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | tenant_id | BIGINT | 租户ID | | short_code | VARCHAR(32) | 二维码唯一短码(8位大写字母+数字) | | sign | VARCHAR(64) | MD5签名值 | | room_id | BIGINT | 绑定房间ID(NULL=未绑定) | | room_no | VARCHAR(32) | 冗余房间号 | | status | VARCHAR(16) | 状态:0=启用, 1=禁用(对应字典 sys_normal_disable) | | batch_no | VARCHAR(32) | 批次号(格式:QR+yyyyMMddHHmmss) | | bind_user_id | BIGINT | 最近绑定人ID | | bind_user_name | VARCHAR(64) | 最近绑定人姓名 | | bind_time | DATETIME | 最近绑定时间 | | unbind_user_id | BIGINT | 最近解绑人ID | | unbind_user_name | VARCHAR(64) | 最近解绑人姓名 | | unbind_time | DATETIME | 最近解绑时间 | | del_flag | BIGINT | 逻辑删除标记 | **唯一索引**: `UNIQUE (tenant_id, short_code)` #### hotel_qr_bind_log(绑定日志表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | tenant_id | BIGINT | 租户ID | | qr_code_id | BIGINT | 二维码ID | | short_code | VARCHAR(32) | 冗余短码 | | room_id | BIGINT | 房间ID | | room_no | VARCHAR(32) | 冗余房间号 | | action_type | VARCHAR(16) | 操作类型:BIND/REBIND/UNBIND | | operator_id | BIGINT | 操作人ID | | operator_name | VARCHAR(64) | 操作人姓名 | | operate_time | DATETIME | 操作时间 | | remark | VARCHAR(256) | 备注 | ### 2.2 Flyway 迁移脚本 **文件**: `forge-server/db/migration/V1.0.86__add_hotel_qr_code_tables.sql` 包含内容: - 4张业务表建表语句(均使用 `CREATE TABLE IF NOT EXISTS`) - 菜单权限资源(`sys_resource`,`tenant_id=1`,带 `NOT EXISTS` 防重复) - 字典数据(`sys_dict_type` + `sys_dict_data`,`tenant_id=1`) ### 2.3 字典数据 | 字典类型 | 字典值 | 标签 | 标签样式 | |----------|--------|------|----------| | sys_normal_disable | 0 | 正常 | success | | sys_normal_disable | 1 | 停用 | danger | | hotel_room_status | VACANT | 空闲 | success | | hotel_room_status | OCCUPIED | 入住 | primary | | hotel_room_status | CLEANING | 打扫中 | warning | | hotel_room_status | MAINTENANCE | 维护中 | danger | | hotel_qr_bind_action | BIND | 绑定 | success | | hotel_qr_bind_action | REBIND | 重绑 | warning | | hotel_qr_bind_action | UNBIND | 解绑 | danger | --- ## 3. 后端 API 接口 ### 3.1 管理端接口(需 Sa-Token 登录) #### 二维码管理 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/hotel/qrcode/page` | 分页查询二维码 | | GET | `/hotel/qrcode/:id` | 查询二维码详情 | | POST | `/hotel/qrcode/batch-generate` | 批量生成二维码 | | POST | `/hotel/qrcode/:id/bind` | 绑定房间 | | POST | `/hotel/qrcode/:id/rebind` | 重新绑定房间 | | POST | `/hotel/qrcode/:id/unbind` | 解绑房间 | | PUT | `/hotel/qrcode/:id/status` | 更新二维码状态 | | POST | `/hotel/qrcode/batch-remove` | 批量删除二维码(逻辑删除) | | POST | `/hotel/qrcode/batch-download` | 批量下载二维码ZIP | | GET | `/hotel/qrcode/:id/bind-logs` | 查询绑定日志 | #### 房间管理 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/hotel/room/page` | 分页查询房间 | | GET | `/hotel/room/:id` | 查询房间详情 | | POST | `/hotel/room` | 新增房间 | | PUT | `/hotel/room` | 修改房间 | | POST | `/hotel/room/remove/:id` | 删除房间 | | GET | `/hotel/room/list-all` | 查询全部房间(下拉用) | #### 房型管理 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/hotel/room-type/list` | 查询房型列表 | | GET | `/hotel/room-type/:id` | 查询房型详情 | | POST | `/hotel/room-type` | 新增房型 | | PUT | `/hotel/room-type` | 修改房型 | | POST | `/hotel/room-type/remove/:id` | 删除房型 | ### 3.2 开放接口(免登录) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/hotel/open/scan?shortCode=xxx&sign=xxx` | 扫码查询二维码信息 | **请求参数**: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | shortCode | String | 是 | 二维码短码 | | sign | String | 是 | 签名校验值 | **响应示例(未绑定)**: ```json { "code": 200, "data": { "qrCodeId": 1234567890, "shortCode": "AB12CD34", "status": "0", "bound": false, "room": null, "bindInfo": null } } ``` **响应示例(已绑定)**: ```json { "code": 200, "data": { "qrCodeId": 1234567890, "shortCode": "AB12CD34", "status": "0", "bound": true, "room": { "roomId": 9876543210, "roomNo": "301", "roomTypeName": "标准双人间" }, "bindInfo": { "operatorName": "张三", "bindTime": "2026-08-10 14:30:00" } } } ``` --- ## 4. 二维码 URL 格式 二维码内容为平台无关的 URL 格式: ``` {baseUrl}/hotel/scan?c={shortCode}&t={tenantId}&s={sign} ``` | 参数 | 说明 | |------|------| | c | 二维码短码(8位) | | t | 租户ID | | s | MD5签名值 = MD5(shortCode + tenantId + secret) | **签名密钥配置**: - 默认值: `hotel_qr_default_secret` - 生产环境: 通过环境变量 `HOTEL_QR_SECRET` 覆盖 --- ## 5. 前端页面 | 页面 | 路径 | 说明 | |------|------|------| | 二维码管理 | `forge-admin-ui/src/views/hotel/qrcode.vue` | AiCrudPage 配置化页面(批量生成、批量删除、批量下载ZIP、单条下载、绑定/重绑/解绑、状态切换、日志查看) | | 房间管理 | `forge-admin-ui/src/views/hotel/room.vue` | AiCrudPage 配置化页面 | | 房型管理 | `forge-admin-ui/src/views/hotel/roomType.vue` | AiCrudPage 配置化页面 | | API 文件 | `forge-admin-ui/src/api/hotel.js` | 统一 API 封装 | --- ## 6. 菜单权限 | 资源ID | 名称 | 类型 | 权限标识 | |--------|------|------|----------| | 2000 | 酒店管理 | 菜单(1) | - | | 2001 | 二维码管理 | 菜单(1) | hotel:qrcode:list | | 2011 | 二维码生成 | 按钮(2) | hotel:qrcode:generate | | 2012 | 二维码绑定 | 按钮(2) | hotel:qrcode:bind | | 2013 | 二维码管理操作 | 按钮(2) | hotel:qrcode:manage | | 2014 | 二维码导出 | 按钮(2) | hotel:qrcode:export | | 2002 | 房间管理 | 菜单(1) | hotel:room:list | | 2021 | 房间新增 | 按钮(2) | hotel:room:add | | 2022 | 房间编辑 | 按钮(2) | hotel:room:edit | | 2023 | 房间删除 | 按钮(2) | hotel:room:delete | | 2003 | 房型管理 | 菜单(1) | hotel:roomtype:list | | 2031 | 房型新增 | 按钮(2) | hotel:roomtype:add | | 2032 | 房型编辑 | 按钮(2) | hotel:roomtype:edit | | 2033 | 房型删除 | 按钮(2) | hotel:roomtype:delete | --- ## 7. Maven 依赖变更 ### 7.1 forge-dependencies(BOM) 新增 ZXing 版本管理: ```xml 3.5.3 com.google.zxing core ${zxing.version} com.google.zxing javase ${zxing.version} ``` 新增 forge-hotel 版本声明: ```xml com.mdframe.forge forge-hotel ${revision} ``` ### 7.2 forge-business/pom.xml 新增子模块: ```xml forge-business-core forge-hotel ``` ### 7.3 forge-admin-server/pom.xml 新增依赖: ```xml com.mdframe.forge forge-hotel ${revision} ``` --- ## 8. 框架层变更 ### SaTokenConfig.java 在 Sa-Token 拦截器中新增 `/hotel/open/**` 路径排除(免登录): ```java // 登录校验拦截器 .notMatch("/hotel/open/**") // API权限拦截器 .excludePathPatterns("/hotel/open/**") ``` --- ## 9. 环境变量 | 变量名 | 必填 | 默认值 | 说明 | |--------|------|--------|------| | HOTEL_QR_SECRET | 否 | hotel_qr_default_secret | 二维码签名密钥(生产环境必须修改) | --- ## 10. 后续扩展预留 | 扩展点 | 说明 | |--------|------| | 钉钉 H5 集成 | 通过 DingTalk SSO 获取员工身份,调用绑定/重绑接口 | | 小程序 openid 绑定 | 在 `/hotel/open/` 下新增小程序专用接口 | | 二维码导出打印 | 使用 EasyExcel 批量导出二维码图片(已实现批量下载ZIP) | | 顾客点餐流程 | 扫码后进入点餐 H5/小程序页面 | | 房间状态实时推送 | WebSocket 推送房间状态变更 |