# AGENTS.md - 酒店二维码模块开发规范 > **重要**: 此文件会被 IDEA QoderWork 插件自动读取,为 AI 助手提供项目上下文和开发规范 **项目**: Forge Admin - 酒店二维码模块 (Hotel QR Code Module) **技术栈**: Spring Boot 3.2 + Vue 3.5 + Naive UI 2.42 + MyBatis-Plus 3.5 **最后更新**: 2026-08-10 --- ## 一、核心开发规范(必须遵守) ### 1.1 后端规范 **启动类**: `ForgeAdminServerApplication`(主应用入口,聚合所有插件) **依赖注入**: ```java @RequiredArgsConstructor // ✅ Lombok 构造器注入 private final HotelQrCodeMapper qrCodeMapper; // ❌ 禁止使用 @Autowired ``` **响应体**: ```java // ✅ 必须使用 RespInfo return RespInfo.success(data); return RespInfo.error("错误信息"); // ❌ 禁止使用 DataResult / ResponseUtil ``` **ID生成**: ```java // ✅ 使用雪花算法(MyBatis-Plus ASSIGN_ID) @TableId(value = "id", type = IdType.ASSIGN_ID) private Long id; // ❌ 禁止使用 UUID / 自增ID ``` **实体继承**: ```java // ✅ 所有实体必须继承 TenantEntity public class HotelQrCode extends TenantEntity { ... } // TenantEntity 包含: tenantId, createBy, createTime, createDept, updateBy, updateTime ``` **逻辑删除**: ```java // ✅ 必须显式声明 @TableLogic @TableLogic(value = "0", delval = "id") private Long delFlag; // Mapper XML 查询必须显式过滤: AND del_flag = 0 ``` **Controller路由**: ```java @RestController @RequestMapping("/hotel") public class HotelQrCodeController { ... } // 实际访问: /hotel/qrcode/page, /hotel/room/page 等 ``` **SQL 规范**: - 查询类 SQL **禁止**在 Service 层用 `LambdaQueryWrapper` 构建 - 必须写在 Mapper XML 中(DataScopeInterceptor 按 mapperMethod 精确匹配) - 例外:仅单表 `selectById`、`insert`、`updateById`、`deleteById` 等内置方法允许 **租户 ID 规则**: - 业务数据的 `tenant_id` **必须设为 `1`**(默认租户),**禁止设 `0`** - `TenantLineInnerInterceptor` 自动追加 `WHERE tenant_id = 当前租户ID` ### 1.2 前端规范 **组件语法**: ```vue ``` **列表页面**: ```vue ``` **字典使用**: ```vue ``` **按钮样式约定**: | 类名 | 颜色 | 场景 | |------|------|------| | `text-primary` | 蓝 | 编辑、查看、绑定、下载 | | `text-warning` | 黄 | 解绑、禁用、重置 | | `text-error` | 红 | 删除 | | `text-success` | 绿 | 启用 | | `text-info` | 灰蓝 | 详情、日志 | --- ## 二、项目架构 ### 2.1 模块位置 ``` forge-server/forge-business/forge-hotel/ # 酒店业务模块 ├── controller/ # REST 控制器 ├── service/ # 服务接口 │ └── impl/ # 服务实现 ├── mapper/ # MyBatis Mapper 接口 + XML ├── domain/ # 数据库实体 ├── dto/ # 请求 DTO ── vo/ # 响应 VO ├── constant/ # 常量定义 └── utils/ # 工具类(二维码生成、签名校验) forge-admin-ui/src/views/hotel/ # 前端页面 ├── qrcode.vue # 二维码管理(AiCrudPage) ├── room.vue # 房间管理(AiCrudPage) └── roomType.vue # 房型管理(AiCrudPage) forge-h5-ui/src/pages/hotel/ # H5 移动端 └── scan-bind.vue # 扫码绑定房间页面 ``` ### 2.2 三端架构 | 端 | 技术 | 部署 | 核心功能 | |---|------|------|---------| | PC 管理后台 | Vue3 + Naive UI + AiCrudPage | PC浏览器 | 批量生成、批量删除、批量下载ZIP、绑定/重绑/解绑、状态管理 | | H5 移动端 | UniApp + html5-qrcode | 手机浏览器(HTTPS) | 员工扫码绑定房间、查看绑定状态 | | 开放接口 | REST API | 免登录 | 顾客扫码查询二维码信息 | --- ## 三、技术栈清单 ### 后端 - Java 17 + Spring Boot 3.2 - MyBatis-Plus 3.5 + 动态数据源 - Sa-Token 1.38(认证授权) - 多租户隔离(TenantLineInnerInterceptor) - ZXing 3.5.3(二维码生成) - MySQL 8.0+ / Redis 6.0+ ### 前端 - Vue 3.5 + Naive UI 2.42 - Vite 7 + Pinia 3 + UnoCSS 66 - AiCrudPage / AiSearch / AiTable(框架标准组件) - html5-qrcode(H5 扫码) --- ## 四、数据库设计 ### 4.1 表结构 **hotel_qr_code(二维码表)**: | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键(雪花算法) | | tenant_id | BIGINT | 租户ID,默认1 | | 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 | 逻辑删除标记(0=未删除,删除时写入主键ID) | **唯一索引**: `UNIQUE (tenant_id, short_code, del_flag)` **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_room_type(房型表)**: | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | tenant_id | BIGINT | 租户ID | | type_name | VARCHAR(64) | 房型名称 | | description | VARCHAR(256) | 房型描述 | | sort_order | INT | 排序号 | | del_flag | BIGINT | 逻辑删除标记 | **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) | 备注 | ### 4.2 字典数据 | 字典类型 | 字典值 | 标签 | 标签样式 | |----------|--------|------|----------| | 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 | --- ## 五、API 接口清单 ### 5.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` | 删除房型 | ### 5.2 开放接口(免登录) | 方法 | 路径 | 说明 | |------|------|------| | GET | `/hotel/open/scan?shortCode=xxx&sign=xxx` | 扫码查询二维码信息 | --- ## 六、二维码 URL 格式 ``` {baseUrl}/#/pages/hotel/scan-bind?c={shortCode}&t={tenantId}&s={sign} ``` | 参数 | 说明 | |------|------| | c | 二维码短码(8位) | | t | 租户ID | | s | MD5签名值 = MD5(shortCode + tenantId + secret) | **签名密钥配置**: - 默认值: `hotel_qr_default_secret` - 生产环境: 通过环境变量 `HOTEL_QR_SECRET` 覆盖 --- ## 七、关键业务逻辑 ### 7.1 批量生成 - 生成数量:10/50/100/200 个一批,上限 500 - 短码:8位大写字母+数字,租户内唯一 - 批次号:QR + yyyyMMddHHmmss - 状态:默认启用(status=0) ### 7.2 绑定/重绑/解绑 - **绑定**:未绑定的二维码可绑定房间,记录绑定人/绑定时间 - **重绑**:已绑定的二维码可重新绑定,覆盖原绑定关系,更新绑定人/绑定时间 - **解绑**:清除绑定关系,记录解绑人/解绑时间(不覆盖绑定信息) - 所有操作均记录到 `hotel_qr_bind_log` 表 ### 7.3 批量删除 - 仅允许删除未绑定房间的二维码 - 已绑定的二维码拒绝删除,提示先解绑 - 逻辑删除(del_flag 写入主键ID) ### 7.4 批量下载ZIP - 勾选多个二维码,后端生成 PNG 图片打包为 ZIP - 文件名以短码命名:`{shortCode}.png` - 单条下载:操作列"下载"按钮 ### 7.5 扫码查询(开放接口) - 免登录,根据 shortCode 查询二维码(忽略租户过滤) - 签名校验:MD5(shortCode + tenantId + secret) - 使用二维码所属租户 ID 设置租户上下文,执行后续查询 --- ## 八、环境变量 | 变量名 | 必填 | 默认值 | 说明 | |--------|------|--------|------| | HOTEL_QR_SECRET | 否 | hotel_qr_default_secret | 二维码签名密钥(生产环境必须修改) | --- ## 九、后续扩展预留 | 扩展点 | 说明 | |--------|------| | 钉钉 H5 集成 | 通过 DingTalk SSO 获取员工身份,调用绑定/重绑接口 | | 小程序 openid 绑定 | 在 `/hotel/open/` 下新增小程序专用接口 | | 顾客点餐流程 | 扫码后进入点餐 H5/小程序页面 | | 房间状态实时推送 | WebSocket 推送房间状态变更 | --- ## 十、给 AI 助手的指令 当协助开发酒店模块时,请: 1. **严格遵循规范**: 使用 `@RequiredArgsConstructor`、`RespInfo`、雪花算法ID、Composition API 2. **使用 AiCrudPage**: 列表页面必须使用 `AiCrudPage` 组件,禁止手动拼接搜索栏 3. **使用字典组件**: 状态/类型等字段必须使用 `DictTag` / `useDict()`,禁止硬编码 4. **SQL 写在 XML**: 查询类 SQL 必须写在 Mapper XML 中,禁止 Service 层用 LambdaQueryWrapper 5. **逻辑删除**: 所有业务表默认逻辑删除,`@TableLogic` 必须显式声明 6. **租户隔离**: 业务数据 `tenant_id=1`,查询自动追加租户过滤 7. **参考现有代码**: 查看 `forge-hotel` 模块中已有实现 **禁止**: - 不使用 `@Autowired`(使用 `@RequiredArgsConstructor`) - ❌ 不使用 `DataResult` / `ResponseUtil`(使用 `RespInfo`) - ❌ 不使用 UUID / 自增ID(使用雪花算法) - ❌ 不在 Service 层构建查询 SQL(写在 Mapper XML) - 不手动拼接搜索栏(使用 AiCrudPage) - ❌ 不硬编码字典值(使用 DictTag / useDict) - ❌ 不设 `tenant_id=0`(必须为 1) --- ## 十一、文件路径 - 后端模块: `forge-server/forge-business/forge-hotel/` - PC前端页面: `forge-admin-ui/src/views/hotel/` - H5前端页面: `forge-h5-ui/src/pages/hotel/` - API文件: `forge-admin-ui/src/api/hotel.js` - 数据库迁移: `forge-server/db/migration/` - 开发文档: `forge-server/forge-business/forge-hotel/酒店二维码模块开发文档.md` --- **配置版本**: v2.0 **维护者**: QoderWork AI Assistant