### 1.3 Forge 已有代码 ``` forge-server/forge-business/forge-hotel/src/main/java/com/mdframe/forge/business/core/hotel/ ├── controller/ │ ├── HotelQrCodeController.java ✅ 二维码管理 │ ├── HotelBusinessHoursController.java ✅ 营业时段管理 │ ├── HotelDishSpecController.java ✅ 菜品规格管理(规格组 + 选项) │ └── open/ │ └── HotelOpenController.java ✅ 开放接口(扫码查询) ├── domain/ │ ├── HotelQrCode.java ✅ 二维码实体 │ ├── HotelQrBindLog.java ✅ 绑定日志实体 │ ├── HotelRoom.java ✅ 房间实体 │ ├── HotelRoomType.java ✅ 房型实体 │ ├── HotelBusinessHours.java ✅ 营业时段实体 │ ├── HotelDishSpecGroup.java ✅ 规格组实体 │ └── HotelDishSpecOption.java ✅ 规格选项实体 ├── dto/ │ ├── QrCodeBatchGenerateDTO.java ✅ │ ├── QrCodeBindDTO.java ✅ │ ├── QrCodeQueryDTO.java ✅ │ ├── HotelRoomDTO.java ✅ │ └── HotelRoomTypeDTO.java ✅ ├── vo/ │ ├── HotelQrCodeVO.java ✅ │ ├── HotelQrBindLogVO.java ✅ │ ├── QrCodeScanVO.java ✅ │ ├── HotelRoomVO.java ✅ │ └── HotelRoomTypeVO.java ✅ ├── mapper/ │ ├── HotelQrCodeMapper.java ✅ │ ├── HotelQrBindLogMapper.java ✅ │ ├── HotelRoomMapper.java ✅ │ ├── HotelRoomTypeMapper.java ✅ │ ├── HotelBusinessHoursMapper.java ✅ │ ├── HotelDishSpecGroupMapper.java ✅ │ └── HotelDishSpecOptionMapper.java ✅ ├── service/ │ ├── HotelQrCodeService.java ✅ │ ├── HotelBusinessHoursService.java ✅ │ ├── HotelDishSpecGroupService.java ✅ │ ├── HotelDishSpecOptionService.java ✅ │ └── impl/ │ ├── HotelQrCodeServiceImpl.java ✅ │ ├── HotelBusinessHoursServiceImpl.java ✅ │ ├── HotelDishSpecGroupServiceImpl.java ✅ │ └── HotelDishSpecOptionServiceImpl.java ✅ ├── constant/ │ └── HotelQrConstants.java ✅ └── utils/ └── QrCodeUtils.java ✅ order/ ✅ 订单管理子包(独立于已有代码) ├── constant/ │ └── HotelOrderConstants.java ✅ 订单状态常量 0~10 + 退单发起方 ├── domain/ │ ├── HotelOrder.java ✅ 订单实体(含 payStatus/payExpireTime/paySource) │ └── HotelOrderItem.java ✅ 订单明细实体 ├── dto/ │ └── OrderCreateDTO.java ✅ 创建订单请求(已移除 payMethod,改用 paySource) ├── vo/ │ ├── HotelOrderVO.java ✅ 订单视图(含内部类 OrderItemVO) │ └── OrderDashboardVO.java ✅ 看板统计视图 ├── mapper/ │ ├── HotelOrderMapper.java ✅ │ └── HotelOrderItemMapper.java ✅ ├── service/ │ ├── HotelOrderService.java ✅ 14+ 个方法接口(含支付/超时取消) │ └── impl/ │ └── HotelOrderServiceImpl.java ✅ 完整状态机 + 退单流程 + 支付超时处理 ├── controller/ │ └── HotelOrderController.java ✅ 15+ 个 REST 接口 pay/ ✅ 支付系统子包(支付宝沙箱 H5 WAP Pay + 安全加固) ├── config/ │ └── AlipayConfig.java ✅ 支付宝配置(appId/密钥/网关/回调地址,@ConfigurationProperties) ├── constant/ │ └── HotelPayConstants.java ✅ 支付常量(payStatus 0/1/3、paySource MOCK/WECHAT/ALIPAY) ├── domain/ │ └── HotelPayLog.java ✅ 支付流水实体(outTradeNo/tradeNo/payAmount/payStatus) ── dto/ │ └── PayCreateDTO.java ✅ 创建支付请求(orderId + paySource) ├── vo/ │ └── PayResultVO.java ✅ 支付结果视图(payStatus/payForm/tradeNo) ├── mapper/ │ ├── HotelPayLogMapper.java ✅ 含 @InterceptorIgnore + 幂等更新 + 按orderId查询 │ └── xml/HotelPayLogMapper.xml ✅ 自定义 SQL(幂等 UPDATE WHERE pay_status != 1) ├── service/ │ ├── HotelPayService.java ✅ 支付接口(createPay/handlePayCallback/queryAlipayTradeStatus) │ └── impl/ │ └── HotelPayServiceImpl.java ✅ 支付宝 WAP Pay + 回调处理 + 安全加固(5层保障) ├── controller/ │ └── open/ │ └── HotelPayController.java ✅ 支付接口(create/payNotify/returnUrl/status/alipayQuery/mockSuccess) ``` forge-admin-ui/src/views/hotel/ ├── qrcode.vue ✅ 二维码管理页面(AiCrudPage) ├── room.vue ✅ 房间管理页面(AiCrudPage) ├── dish.vue ✅ 菜品管理页面(AiCrudPage,含图片预览/上下架/售罄) ├── dishCategory.vue ✅ 菜品分类管理页面(AiCrudPage,含启禁用) ├── dishSpec.vue ✅ 菜品规格管理(AiCrudPage + 选项管理弹窗) ├── businessHours.vue ✅ 营业时段管理(AiCrudPage,时间段下拉选择) └── order.vue ✅ 订单管理(AiCrudPage + 看板统计 + 流程操作 + 详情弹窗) forge-admin-ui/src/api/ └── hotel.js ✅ 酒店模块 API(含菜品/分类/规格/营业时段/订单接口) forge-h5-ui/src/pages/hotel/ ├── scan-bind.vue ✅ 扫码绑定页面 └── customer/ ├── room-confirm.vue ✅ 房号确认入口页(扫码验证/房间卡片/开始点餐) ├── menu.vue ✅ 点餐菜单页 Tab1(配送信息栏/Banner/搜索/分类/菜品列表/购物车浮层) ├── dish-detail.vue ✅ 菜品详情页(大图/规格选择/加料/备注/数量/加入购物车) ├── cart.vue ✅ 购物车页 Tab3(商品列表/数量控制/备注/费用汇总/结算) ├── order-confirm.vue ✅ 确认下单页(配送信息/送达时间/明细/提交,已移除硬编码支付方式) ├── pay.vue ✅ 支付确认页(支付宝 H5 WAP Pay + 轮询 + 主动查询兜底 + 倒计时) ├── order-status.vue ✅ 订单状态页 Tab2(进度条/状态卡片/10秒轮询/自定义退单弹窗) └── orders.vue ✅ 订单列表页 Tab2(订单卡片列表/分页加载/状态标签/待支付去支付按钮) forge-h5-ui/src/components/hotel/ └── HotelTabBar.vue ✅ 酒店顾客端 3-tab TabBar(点餐/订单/购物车) forge-h5-ui/src/styles/ └── hotel-theme.css ✅ 亚朵深墨绿主题 CSS 变量(--h-pri/--h-bg/--h-txt 等) forge-h5-ui/src/store/modules/ └── hotel-order.js ✅ Pinia 购物车 Store(roomInfo/cartItems/orderNote,持久化) forge-h5-ui/src/api/ └── index.js ✅ 新增 12+ 个顾客端 API(扫码/分类/菜品/订单CRUD/退单/支付/支付宝查询) ``` --- ## 二、模块迁移状态总览 | # | 模块 | 后端 | 数据库 | 前端 PC | 前端 H5 | 状态 | |---|------|------|--------|--------|--------|------| | 1 | room(房间/房型管理) | ✅ | ✅ | ✅ | ✅ | **已完成** | | 2 | qrcode(二维码管理) | ✅ | ✅ | ✅ | ✅ | **已完成** | | 3 | open(开放扫码接口) | ✅ | — | — | ✅ | **已完成** | | 4 | dish-spec(菜品规格管理) | ✅ | ✅ | ✅ | — | **已完成** | | 5 | business-hours(营业时段) | ✅ | ✅ | ✅ | — | **已完成** | | 6 | hotelconfig(酒店基础配置) | ❌ | ❌ | ❌ | — | **暂缓**(暂不需要,配送费 + 预计配送时长待讨论) | | 7 | dish(菜品管理) | ✅ | ✅ | ✅ | — | **核心已完成**(加料/日志待开发) | | 8 | order(订单管理) | ✅ | ✅ | ✅ | ✅ | **全部完成**(后端+PC管理端+H5顾客端+支付系统) | | 8.1 | pay(支付系统) | ✅ | ✅ | — | ✅ | **全部完成**(支付宝沙箱 H5 WAP Pay + 安全加固 + 前端轮询兜底) | | 9 | notification(实时通知) | ✅ | — | ✅ | — | **已完成**(SSE + Web Audio声音 + 桌面通知 + 防抖合并) | --- ## 三、各模块详细任务清单 ### 3.1 hotelconfig — 酒店基础配置 ⏸️ 暂缓 > **状态**: 暂缓开发。暂时用不到,其中**配送费**和**预计配送时长**功能待后续讨论后再实现。 #### 后端(待开发) - [ ] 实体:`HotelConfig.java` — 酒店基础配置(名称/主题/配送费/预计配送时长) - [ ] Mapper: `HotelConfigMapper.java` + XML - [ ] Service: `HotelConfigService.java` — 获取/保存配置 - [ ] Controller: `HotelConfigController.java` — 配置接口 #### 数据库(待开发) - [ ] 建表:`hotel_config`(IF NOT EXISTS) - [ ] 菜单:酒店配置管理(sys_resource) #### 前端(待开发) - [ ] 页面:`forge-admin-ui/src/views/hotel/config.vue` — 酒店基础配置表单 #### ⚠️ 待讨论项 - **配送费规则**:按距离/按区域/固定费用?是否支持阶梯定价? - **预计配送时长**:固定值还是动态计算?单位分钟? - 这两项功能需要与业务方确认具体需求后再开发 #### 源框架参考 | 文件 | 说明 | |------|------| | `hotelconfig/domain/HotelConfig.java` | 配置实体 | | `hotelconfig/domain/HotelBusinessHours.java` | 营业时段实体 | | `hotelconfig/controller/HotelConfigController.java` | 全部接口 | | `hotelconfig/service/HotelConfigService.java` | 全部业务逻辑 | | `hotelconfig/mapper/xml/HotelConfigMapper.xml` | 配置查询 SQL | | 前端:`views/hotel/admin/HotelConfigManagement.vue` | 配置管理页面 | | 前端:`views/hotel/admin/BusinessHoursManagement.vue` | 营业时段页面 | | 前端:`views/hotel/admin/BusinessHoursForm.vue` | 营业时段表单 | | 前端:`api/hotel/HotelConfigService.js` | 配置 API | | 前端:`api/hotel/HotelBusinessHoursService.js` | 营业时段 API | --- ### 3.2 dish — 菜品管理 ⭐⭐⭐ #### 后端 - [x] 实体:`HotelDish.java` — 菜品主表 - [x] 实体:`HotelDishCategory.java` — 菜品分类 - [x] 实体:`HotelDishSpecGroup.java` — 规格组(源框架同时存在 spec 和 spec_group,Forge 统一用 spec_group) - [x] 实体:`HotelDishSpecOption.java` — 规格选项 - [x] 实体:`HotelDishAddition.java` — 加料 - [x] 实体:`HotelDishLog.java` — 操作日志 - [x] DTO: `HotelDishDTO.java` — 菜品传输对象 - [x] DTO: `HotelDishCategoryDTO.java` — 分类传输对象 - [x] DTO: `DishBatchOperationDTO.java` — 批量操作传输对象 - [x] VO: `HotelDishVO.java` / `HotelDishCategoryVO.java` — 视图对象 - [x] Mapper: `HotelDishMapper.java` + XML(含管理后台分页查询) - [x] Mapper: `HotelDishCategoryMapper.java` + XML(含分页查询) - [x] Mapper: `HotelDishSpecGroupMapper.java` - [x] Mapper: `HotelDishSpecOptionMapper.java` - [x] Mapper: `HotelDishAdditionMapper.java` + XML - [x] Mapper: `HotelDishLogMapper.java` - [x] Service: `HotelDishService.java` — 菜品 CRUD + 上下架 + 售罄/恢复 + 删除 - [x] Service: `HotelDishCategoryService.java` — 分类 CRUD + 启用/禁用 - [x] Service: `HotelDishSpecGroupService.java` — 规格组 CRUD + 级联删除选项 - [x] Service: `HotelDishSpecOptionService.java` — 规格选项 CRUD - [x] Controller: `HotelDishController.java` — 菜品接口(分页/详情/新增/修改/删除/上下架/售罄/恢复) - [x] Controller: `HotelDishCategoryController.java` — 分类接口(分页/新增/修改/删除/启禁用) - [x] Controller: `HotelDishSpecController.java` — 规格组 + 规格选项统一接口 - [ ] Controller: 加料/日志 Controller(待开发) #### 数据库 - [x] 建表:`hotel_dish`(IF NOT EXISTS)— 含 image(主图)+ images(附加图片)字段 - [x] 建表:`hotel_dish_category`(IF NOT EXISTS) - [x] 建表:`hotel_dish_spec_group`(IF NOT EXISTS) - [x] 建表:`hotel_dish_spec_option`(IF NOT EXISTS) - [x] 建表:`hotel_dish_addition`(IF NOT EXISTS) - [x] 建表:`hotel_dish_log`(IF NOT EXISTS) - [x] 字典:`hotel_dish_status`(ON_SALE/OFF_SHELF) - [x] 字典:`hotel_dish_sold_out`(0=正常/1=售罄) - [x] 菜单:菜品管理 + 菜品分类管理(sys_resource) - [x] 菜单权限:菜品增删改查按钮权限 - 迁移脚本:`V1.0.101__add_hotel_dish_module_tables.sql` #### 前端 - [x] 页面:`forge-admin-ui/src/views/hotel/dish.vue` — 菜品管理(AiCrudPage) - 序号列、主图缩略图(AuthImage)、全屏图片预览(主图 + 副图左右切换) - 编辑按钮(仅下架可编辑)、上架/下架、售罄/恢复、删除 - 编辑表单:主厨推荐 (Switch)、状态 (Radio)、价格/制作时长/排序 (inputNumber)、主图/附加图片 (imageUpload) - [x] 页面:`forge-admin-ui/src/views/hotel/dishCategory.vue` — 菜品分类管理(AiCrudPage) - 编辑按钮、启用/禁用操作 - [x] API: `forge-admin-ui/src/api/hotel.js` 中追加菜品/分类相关接口 #### 源框架参考 | 文件 | 说明 | |------|------| | `dish/domain/HotelDish.java` | 菜品实体 | | `dish/domain/HotelDishCategory.java` | 分类实体 | | `dish/domain/HotelDishSpecGroup.java` | 规格组实体 | | `dish/domain/HotelDishSpecOption.java` | 规格选项实体 | | `dish/domain/HotelDishAddition.java` | 加料实体 | | `dish/domain/HotelDishLog.java` | 日志实体 | | `dish/controller/HotelDishController.java` | 菜品全部接口 | | `dish/controller/HotelDishCategoryController.java` | 分类接口 | | `dish/controller/HotelDishSpecGroupController.java` | 规格组接口 | | `dish/controller/HotelDishSpecOptionController.java` | 规格选项接口 | | `dish/service/HotelDishService.java` | 菜品业务逻辑(417 行) | | `dish/service/HotelDishCategoryService.java` | 分类业务逻辑 | | `dish/mapper/xml/HotelDishMapper.xml` | 菜品 SQL | | `dto/DishBatchOperationDTO.java` | 批量操作 DTO | | 前端:`views/hotel/dish/DishManagement.vue` | 菜品管理页面 | | 前端:`views/hotel/dish/DishForm.vue` | 菜品表单 | | 前端:`views/hotel/dish/CategoryManagement.vue` | 分类管理 | | 前端:`views/hotel/dish/CategoryForm.vue` | 分类表单 | | 前端:`api/hotel/HotelDishService.js` | 菜品 API | | 前端:`api/hotel/HotelDishSpecService.js` | 规格 API | #### 注意事项 - 源框架同时存在 `hotel_dish_spec` 和 `hotel_dish_spec_group` 两张表,Forge 统一使用 `hotel_dish_spec_group` - 源框架删除菜品时校验未完成订单 → 需要依赖 order 模块(可先预留校验接口,order 完成后再联通) - 菜品价格使用 `BigDecimal`,金额单位与源框架保持一致(元) --- ### 3.3 order — 订单管理 ⭐⭐⭐⭐(最复杂) > **状态**: 全部完成。后端 + 前端 PC 管理端 + H5 顾客点餐端 + 支付系统均已完成。 #### 后端 - [x] 实体:`HotelOrder.java` — 订单主表(Integer status,0~10 数字状态,含 payStatus/payExpireTime/paySource) - [x] 实体:`HotelOrderItem.java` — 订单明细(冗余 dishName/specDesc/additionsDesc) - [x] DTO: `OrderCreateDTO.java` — 创建订单请求(已移除 payMethod,改用 paySource) - [x] VO: `HotelOrderVO.java` — 订单视图对象(含内部类 OrderItemVO + itemCount) - [x] VO: `OrderDashboardVO.java` — 看板统计响应 - [x] Mapper: `HotelOrderMapper.java` + XML(含看板统计/今日营收/订单号生成,6 个自定义 SQL) - [x] Mapper: `HotelOrderItemMapper.java` + XML(按订单ID查询 + 批量插入) - [x] Service: `HotelOrderService.java` — 14+ 个方法接口(含完整 Javadoc + 支付/超时取消) - [x] Service: `HotelOrderServiceImpl.java` — 完整状态机 + 退单流程 + 菜品销量累加 + 支付超时处理 - [x] Controller: `HotelOrderController.java` — 15+ 个 REST 接口(查询3 + 操作6 + 退单4 + 创建1 + 看板1 + 支付相关) - [x] 常量:`HotelOrderConstants.java` — 状态 0~10 + 退单发起方 #### 数据库 - [x] 建表:`hotel_order`(IF NOT EXISTS)— 23+ 个字段 + 4 个索引(V1.0.104 建表 + V1.0.105 支付字段扩展) - [x] 建表:`hotel_order_item`(IF NOT EXISTS)— 13 个字段 + 1 个索引 - [x] 字典:`hotel_order_status`(0~10 数字状态,对应中文标签 + list_class 颜色,V1.0.104 + V1.0.105 补充 0/10) - [x] 字典:`hotel_pay_method`(MOCK/CASH/ONLINE/CREDIT) - [x] 字典:`hotel_delivery_time_type`(ASAP/CUSTOM) - [x] 菜单:订单管理(sys_resource) - [x] 菜单权限:订单查询/接单/拒单/备餐/配送/退单审核 6 个按钮权限 - 迁移脚本:`V1.0.104__add_hotel_order_module.sql`(建表 + 字典 + 菜单) - 迁移脚本:`V1.0.105__add_hotel_order_payment_fields.sql`(支付字段 + 状态 0/10 + MySQL 8 兼容) #### 前端 - [x] 页面:`forge-admin-ui/src/views/hotel/order.vue` — 订单管理(AiCrudPage + 看板统计 + 流程操作 + 详情弹窗) - 顶部看板统计卡片(待接单/备餐中/配送中/今日订单/今日营收) - 搜索筛选(房间号/订单状态/联系人/支付方式) - 操作列按状态动态显示(接单/拒单/备餐/出餐/配送/完成/同意退单/驳回/前台退单) - 订单详情弹窗(基本信息 + 金额 + 时间记录 + 菜品明细表格) - 原因输入弹窗(拒单/退单审核共用) - [x] API: `forge-admin-ui/src/api/hotel.js` 中追加 14 个订单接口函数 #### 支付系统(pay 子包)⭐⭐⭐ > **状态**: 全部完成。支付宝沙箱 H5 WAP Pay 全链路集成 + 5 层安全加固 + 前端轮询兜底。 ##### 后端 - [x] 配置:`AlipayConfig.java` — 支付宝配置(appId/privateKey/alipayPublicKey/gatewayUrl/notifyUrl/returnUrl,@ConfigurationProperties 注入) - [x] 常量:`HotelPayConstants.java` — 支付状态常量(0=待支付/1=成功/3=超时)+ 支付渠道(MOCK/WECHAT/ALIPAY) - [x] 实体:`HotelPayLog.java` — 支付流水(outTradeNo/tradeNo/payAmount/payStatus/payTime/notifyContent) - [x] DTO: `PayCreateDTO.java` — 创建支付请求(orderId + paySource) - [x] VO: `PayResultVO.java` — 支付结果(payStatus/payForm/tradeNo) - [x] Mapper: `HotelPayLogMapper.java` + XML - `@InterceptorIgnore(tenantLine = "true")` 绕过租户拦截(回调无登录态) - `updatePayStatusSuccessByIdempotent` — 数据库级幂等更新(`UPDATE WHERE pay_status != 1`) - `selectLatestByOrderId` — 按订单 ID 查最新支付流水(主动查询兜底用) - [x] Service: `HotelPayService.java` — 支付接口(createPay/handlePayCallback/queryAlipayTradeStatus/queryPayStatus) - [x] Service: `HotelPayServiceImpl.java` — 完整支付实现 - `createPay()` — 根据 paySource 创建支付(ALIPAY → AlipayTradeWapPayRequest → 返回 payForm HTML) - `handlePayCallback()` — 支付宝异步回调处理(拆分两步:查 payLog 获取 tenantId → TenantContextHolder.executeWithTenant 包裹业务处理) - `queryAlipayTradeStatus()` — 主动查询支付宝侧订单状态(回调丢失时的兜底机制) - [x] Controller: `HotelPayController.java` — 5 个接口 - `POST /hotel/open/pay/create` — 创建支付(返回 payForm/tradeNo) - `POST /hotel/open/pay/payNotify` — 支付宝异步回调(签名验证 + 金额校验 + app_id 校验 + 幂等更新 + 异常返回 fail 触发重试) - `GET /hotel/open/pay/returnUrl` — 支付宝同步跳转(前端轮询检测支付状态) - `GET /hotel/open/pay/status` — 查询支付状态(前端轮询用) - `GET /hotel/open/pay/alipayQuery` — 主动查询支付宝侧订单状态(兜底机制) - `POST /hotel/open/pay/mockSuccess` — Mock 支付(开发调试用) ##### 数据库 - [x] 建表:`hotel_pay_log`(IF NOT EXISTS)— 支付流水表(outTradeNo/tradeNo/payAmount/payStatus/payTime/notifyTime/notifyContent) - [x] 迁移脚本:`V1.0.106__add_hotel_pay_log_table.sql` ##### 安全加固(5 层保障) | # | 保障层 | 说明 | |---|--------|------| | 1 | RSA2 签名验证 | `AlipaySignature.rsaCheckV1` 验证回调签名,防伪造 | | 2 | app_id 校验 | 验证回调中的 app_id 与配置一致,防跨应用攻击 | | 3 | 金额校验 | 回调金额与订单金额比对,不一致则拒绝 | | 4 | 数据库级幂等 | `UPDATE WHERE pay_status != 1` 利用行锁保证原子性,防并发重复处理 | | 5 | 主动查询兜底 | 前端轮询超时后调用 `/alipayQuery` 主动查支付宝侧状态,补偿丢失的回调 | ##### 异常场景覆盖 | 场景 | 防护措施 | |------|----------| | 事务处理中断电 | `@Transactional` 保证原子性,全部回滚 | | 回调时网络中断 | 返回 "fail",支付宝 24h 内自动重试(约 8 次) | | 并发重复回调 | 数据库 `UPDATE WHERE pay_status != 1` 行锁幂等 | | 回调全部丢失 | 前端 `/alipayQuery` 主动查支付宝侧订单状态 | | 服务器长时间宕机 | 支付宝重试 + 恢复后自动处理 | ##### 前端(pay.vue) - [x] 支付宝 H5 WAP Pay:后端返回 payForm(HTML 表单),前端渲染后自动提交跳转支付宝收银台 - [x] 支付环境自动识别:条件编译(MP-WEIXIN/MP-ALIPAY/H5)+ UA 检测(微信内置浏览器 → 微信支付,其他 → 支付宝) - [x] 递归 setTimeout 轮询:首次延迟 3 秒,间隔 2 秒,最多 60 次(120 秒),检测支付状态 - [x] 轮询超时兜底:超时后调用 `/alipayQuery` 主动查询支付宝侧订单状态 - [x] 页面加载自动轮询:从支付宝返回后自动检测支付状态(无需用户操作) - [x] 已支付直接跳转:订单 payStatus=1 时直接跳转订单状态页 #### H5 顾客端(forge-h5-ui) - [x] 基础设施: - `api/index.js` — 新增 12+ 个顾客端 API 函数(含支付/支付宝查询) - `store/modules/hotel-order.js` — Pinia 购物车 Store(roomInfo/cartItems/orderNote,persist 持久化) - `styles/hotel-theme.css` — 亚朵深墨绿主题 CSS 变量(`--h-pri: #2D5016` 等) - `components/hotel/HotelTabBar.vue` — 3-tab 自定义 TabBar(点餐/订单/购物车),使用 `uni.reLaunch` 导航(已移除"我的"tab,避免与系统 tabBar 冲突) - `pages.json` — 注册 8 个顾客端页面路由 - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/room-confirm.vue` — 房号确认入口页 - 扫码验证房间(调用 `/hotel/open/scan` 免登录接口) - 房间卡片展示(房间号 + 房型)、验证成功动画、开始点餐按钮 - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/menu.vue` — 点餐菜单页(Tab1) - 配送信息栏(房间号/房型)、Banner、搜索框 - 分类标签横向滚动、菜品列表(图片/价格/加入购物车) - 购物车浮层(数量角标/总价/去结算) - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/dish-detail.vue` — 菜品详情页 - 大图展示、规格选择(必选/可选标签)、加料选择(多选) - 特殊要求备注、数量控制、加入购物车(含规格合并逻辑) - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/cart.vue` — 购物车页(Tab3) - 商品列表(图片/规格描述/数量控制)、订单备注 - 费用汇总(菜品小计 + 配送费)、结算按钮 - **已修复**: 结算按钮添加 `box-sizing: border-box` 防止越界 - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/order-confirm.vue` — 确认下单页 - 配送信息(房间号/联系人/联系电话)、送达时间选择(立即/30分钟/1小时) - 订单明细、提交订单(调用 `/hotel/order` 创建) - **已修复**: `unitPrice` 字段从 `item.price`(基础价)改为 `item.unitPrice`(含规格/加料加价) - **已清理**: 移除硬编码的"支付方式"卡片(非小程序自动适配) - **已修复**: 提交按钮添加 `box-sizing: border-box` 防止越界 - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/pay.vue` — 支付确认页 - 金额展示(从后端 API 获取真实金额,非 URL 参数) - 支付宝 H5 WAP Pay(payForm 渲染 + 自动提交跳转收银台) - 支付环境自动识别(条件编译 + UA 检测) - 递归 setTimeout 轮询(首次 3 秒延迟,间隔 2 秒,最多 120 秒) - 轮询超时兜底(主动查询支付宝侧订单状态) - 返回修改按钮(redirectTo 到菜单页,因购物车已清空) - loading 状态、支付倒计时 - **已清理**: 移除"支付方式"卡片(非小程序自动适配) - **已修复**: 支付按钮添加 `box-sizing: border-box` 防止越界 - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/order-status.vue` — 订单状态页(Tab2) - 状态大卡片(图标 + 文本 + 提示,渐变色按状态区分) - 水平进度条(已下单→已接单→备餐中→已出餐→配送中→已送达) - 退单/拒单通知卡片(显示原因) - 配送信息 + 订单明细 + 订单信息三个区块 - **10 秒轮询**自动刷新(未完成订单) - 退单申请自定义弹窗(标题 + 提示文案 + 原因输入框 + 取消/确定按钮,替代 uni.showModal) - [x] 页面:`forge-h5-ui/src/pages/hotel/customer/orders.vue` — 订单列表页(Tab2) - 订单卡片列表(订单号/状态标签/菜品摘要/时间/金额) - 分页加载(`pageNum` + `pageSize`)、退单原因显示 - 待支付订单(status=0)显示"去支付"按钮 - 点击待支付订单跳转支付页,其他订单跳转订单状态详情 #### 源框架参考 | 文件 | 说明 | |------|------| | `order/domain/HotelOrder.java` | 订单实体 | | `order/domain/HotelOrderItem.java` | 订单明细实体 | | `order/controller/HotelOrderController.java` | 全部接口(430 行) | | `order/service/HotelOrderService.java` | 订单业务逻辑(749 行) | | `order/mapper/xml/HotelOrderMapper.xml` | 订单 SQL | | `order/mapper/xml/HotelOrderItemMapper.xml` | 明细 SQL | | `dto/OrderCreateDTO.java` | 创建订单 DTO | | `dto/OrderDashboardDTO.java` | 看板 DTO | | 前端:`views/hotel/hotelfront/HotelFrontOrders.vue` | 前台订单页面 | | 前端:`views/hotel/kitchen/KitchenOrders.vue` | 厨房订单页面 | | 前端:`views/hotel/restaurant/RestaurantOrders.vue` | 餐厅订单页面 | | 前端:`views/hotel/customer/CustomerMenu.vue` | 顾客点餐页面 | | 前端:`api/hotel/HotelOrderService.js` | 订单 API | #### 订单状态机(数字编号 1~9) ``` 0-PENDING_PAY(待支付) └── → 超时自动取消 → 10-TIMEOUT_CANCELLED(超时取消) └── → 支付成功 → 1-PLACED(待接单) 1-PLACED(待接单) ├── → 2-ACCEPTED(已接单)→ 3-PREPARING(备餐中)→ 4-READY(已出餐)→ 5-DELIVERING(配送中)→ 6-COMPLETED(已完成) ├── → 7-REJECTED(已拒单) └── → 9-REFUNDED(已退单,未接单时直接退) 2-ACCEPTED(已接单) └── → 8-REFUND_REQUESTED(退单待审核) ├── → 9-REFUNDED(审核通过) ── → 2-ACCEPTED(审核驳回,恢复) ``` #### 注意事项 - ~~源框架使用 `synchronized` 防止并发接单~~ → Forge 当前版本未加锁,后续高并发场景需补充 Redisson 分布式锁 - ✅ 源框架创建订单时自动计算金额(不信任前端价格)→ Forge 已保持此安全策略 - ✅ 源框架订单完成后自动累加菜品销量 → 已实现(`incrementDishSales`) - ✅ 源框架退单流程较复杂(客户退单 + 前台退单 + 审核退单)→ 已完整迁移 - 订单状态使用数字 0~10(0=待支付, 1~9 原有状态, 10=超时取消),非英文字符串常量 - 金额使用 `BigDecimal` + 元(与 dish 模块一致),编码规范要求 bigint + 分但为模块一致性保持 DECIMAL --- ### 3.4 notification — 实时通知 ⭐⭐ > **状态**: 已完成。后端 SSE 通知 + 前端声音提醒 + 桌面通知 + 防抖合并。 #### 后端 - [x] Manager: `SseEmitterManager.java` — SSE 长连接管理 + 广播(ConcurrentHashMap + AtomicInteger)+ 远程接收(receiveNewOrderFromRemote) - [x] Service: `OrderNotificationService.java` — 通知广播服务(notifyNewOrder + notifyRefundRequest) - [x] Controller: `NotificationController.java` — SSE 端点(subscribe/unsubscribe/connections/remote/notifyNewOrder) - [x] 集成: `HotelPayServiceImpl.java` — 支付成功后发布 NEW_ORDER 通知(支持跨服务 HTTP 调用) - [x] 集成: `HotelOrderServiceImpl.java` — 客户申请退单时发布 REFUND_REQUEST 通知 - [x] 跨服务通信: 8583(AppServer)支付成功后通过 HTTP POST 调用 8580(AdminServer)`/hotel/notification/remote/notifyNewOrder` 接口,解决双服务 SSE 内存不共享问题 - [x] Sa-Token 白名单: 添加 `/hotel/notification/remote/**` 到免登录路径(服务间调用无登录态) #### 数据库 - 无需新建表(直接通过 SSE 推送,不使用 Redis Pub/Sub,单 JVM 足够) #### 前端 - [x] Composable: `useOrderNotification.js` — SSE 订阅 + MP3 声音 + 桌面通知 + 防抖合并 + Chrome 自动播放策略绕过 - [x] 集成: `order.vue` — 接入 SSE 通知(声音提醒 + Naive UI 通知 + 看板/列表自动刷新 + 连接状态指示器 + 页面刷新自动检测待接单订单) - [x] 音频文件: `forge-admin-ui/public/女生-订单提醒.mp3` — MP3 语音提醒文件 #### 技术决策 - 不使用 Redis Pub/Sub(单 JVM 部署,直接调用 SseEmitterManager 即可,省去中间层) - SSE 端点使用 `@SaIgnore` 跳过登录校验(EventSource 无法携带 Authorization Header) - 声音使用 MP3 文件(`/女生-订单提醒.mp3`),通过 Audio 对象播放 - 3 秒防抖窗口合并多个同时到达的通知(避免弹窗叠加) - 绿色呼吸灯指示 SSE 连接状态(看板工具栏右侧) - **跨服务通信**:PC端(8580 AdminServer)和移动端(8583 AppServer)是独立 JVM 进程,SSE 连接存储在各自内存中。8583 支付成功后通过 HTTP POST 调用 8580 的 `/hotel/notification/remote/notifyNewOrder` 接口,由 8580 推送 SSE 事件给 PC 端 - **服务类型判断**:通过 `@Value("${server.type:admin}")` 注入自定义配置属性判断当前服务类型(`admin` 或 `app`),在两个服务的 `application.yml` 中分别配置 `server.type: admin/app` - **Chrome 自动播放策略**:页面加载时用户未交互,`audio.play()` 会被阻止。通过监听首次 `click/keydown` 事件,将播放失败的声音加入待播放队列,用户首次交互后自动补播 - **页面刷新触发语音**:通过 `watch(connected, ...)` 监听 SSE 连接状态,连接成功后自动查询待接单订单(status=1)并触发语音提醒。重置按钮不触发 --- ## 四、框架适配速查表 | 适配项 | jeeplus(源) | Forge(目标) | |--------|--------------|--------------| | 实体基类 | `BaseEntity` | `TenantEntity`(含 tenantId + 审计字段) | | ID 生成 | `UUID.randomUUID()` | `@TableId(type = IdType.ASSIGN_ID)` 雪花算法 | | 响应体 | `ResponseEntity` / `ResponseUtil` | `RespInfo.success(data)` / `RespInfo.error(msg)` | | 注入方式 | `@Resource` | `@RequiredArgsConstructor` + `private final` | | 权限注解 | `@PreAuthorize("hasAuthority('xxx')")` | `@SaCheckPermission("xxx")` | | 日志注解 | `@ApiLog` | `@OperationLog` | | SQL 位置 | Service 层 `QueryWrapper` | Mapper XML(DataScopeInterceptor 要求) | | 逻辑删除 | 手动 `setDelFlag(1)` + `updateById` | `@TableLogic(value="0", delval="id")` 自动 | | 租户隔离 | 无 | `TenantLineInnerInterceptor` 自动追加 `tenant_id` | | 字典 | 硬编码状态值 | `DictSelect` / `DictTag` / `useDict()` | | 前端列表 | 手写 NInput/NSelect | `AiCrudPage` 配置化 | | 分页参数 | `Page` | `pageNum` + `pageSize`(`@RequestParam`) | | 分布式锁 | `synchronized` | Redisson(`@Idempotent` 或手动) | --- ## 五、建议开发顺序 ``` ✅ 1. room(房间/房型管理) ← 已完成 ✅ 2. qrcode(二维码管理) ← 已完成 ✅ 3. open(开放扫码接口) ← 已完成 ✅ 4. dish-spec(菜品规格管理) ← 已完成 ✅ 5. business-hours(营业时段)← 已完成 ⏸️ 6. hotelconfig(酒店配置) ← 暂缓(配送费/配送时长待讨论) 7. dish(加料/日志) ← 待开发 ✅ 8. order(订单管理) ← 全部完成(后端+PC管理端+H5顾客端+支付系统) ✅ 9. notification(实时通知) ← 已完成(SSE + 声音提醒 + 桌面通知) ``` --- ## 六、数据库表汇总 ### 已完成(Forge 已有) | 表名 | 说明 | |------|------| | `hotel_qr_code` | 二维码表 | | `hotel_qr_bind_log` | 二维码绑定日志表 | | `hotel_room` | 房间表 | | `hotel_room_type` | 房型表 | ### 已完成(order 模块) | 表名 | 说明 | 迁移脚本 | |------|------|--------| | `hotel_order` | 订单主表(23+字段 + 4索引,V1.0.105 新增 payStatus/payExpireTime/paySource) | V1.0.104 + V1.0.105 | | `hotel_order_item` | 订单明细表(13字段 + 1索引) | V1.0.104 | ### 已完成(pay 模块) | 表名 | 说明 | 迁移脚本 | |------|------|--------| | `hotel_pay_log` | 支付流水表(outTradeNo/tradeNo/payAmount/payStatus/payTime/notifyContent) | V1.0.106 | ### 待创建 | 表名 | 说明 | 所属模块 | |------|------|--------| | `hotel_config` | 酒店基础配置 | hotelconfig(暂缓) | ### 已完成(dish + dish-spec + business-hours 模块)![img.png](img.png) | 表名 | 说明 | 迁移脚本 | |------|------|--------| | `hotel_dish` | 菜品(含主图/附加图片/主厨推荐/售罄/上下架) | V1.0.101 | | `hotel_dish_category` | 菜品分类 | V1.0.101 | | `hotel_dish_spec_group` | 菜品规格组 | V1.0.101(建表)+ V1.0.102(菜单) | | `hotel_dish_spec_option` | 规格选项 | V1.0.101(建表) | | `hotel_dish_addition` | 加料 | V1.0.101 | | `hotel_dish_log` | 菜品操作日志 | V1.0.101 | | `hotel_business_hours` | 营业时段 | V1.0.103(建表 + 菜单 + 字典) | ### 已完成字典 | 字典类型 | 说明 | 迁移脚本 | |---------|------|--------| | `hotel_dish_status` | 菜品状态(在售/下架) | V1.0.101 | | `hotel_dish_sold_out` | 售罄状态(正常/售罄) | V1.0.101 | | `hotel_meal_type` | 餐段类型(早餐/午餐/晚餐) | V1.0.103 | | `hotel_business_hours_status` | 营业时段状态(启用/禁用) | V1.0.103 | ### 已完成字典(order 模块) | 字典类型 | 说明 | 迁移脚本 | |---------|------|--------| | `hotel_order_status` | 订单状态(0~10,含待支付/超时取消) | V1.0.104 + V1.0.105 | | `hotel_pay_method` | 支付方式(MOCK/CASH/ONLINE/CREDIT) | V1.0.104 | | `hotel_delivery_time_type` | 配送时间类型(ASAP/CUSTOM) | V1.0.104 | ### 待新增字典 | 字典类型 | 说明 | 所属模块 | |---------|------|--------| | (暂无) | | | --- ## 七、前端页面汇总 ### 已完成 | 页面 | 路径 | 组件 | 说明 | |------|------|------|------| | 二维码管理 | `views/hotel/qrcode.vue` | AiCrudPage | 批量生成/绑定/解绑/下载 | | 房间管理 | `views/hotel/room.vue` | AiCrudPage | 房间/房型 CRUD | | 菜品管理 | `views/hotel/dish.vue` | AiCrudPage | 图片预览/上下架/售罄/主厨推荐 | | 菜品分类 | `views/hotel/dishCategory.vue` | AiCrudPage | 分类 CRUD + 启禁用 | | 菜品规格 | `views/hotel/dishSpec.vue` | AiCrudPage | 规格组列表 + 选项管理弹窗 | | 营业时段 | `views/hotel/businessHours.vue` | AiCrudPage | 时段列表 + 时间段下拉选择 + 启禁用 | | 扫码绑定 (H5) | `forge-h5-ui/src/pages/hotel/scan-bind.vue` | UniApp | 扫码绑定房间 | ### 已完成(order 模块 — PC 管理端) | 页面 | 路径 | 组件 | 说明 | |------|------|------|------| | 订单管理 | `views/hotel/order.vue` | AiCrudPage | 看板统计 + 流程操作 + 详情弹窗 + 退单审核 | ### 已完成(order 模块 — H5 顾客端) | 页面 | 路径 | Tab | 说明 | |------|------|-----|------| | 房号确认 | `forge-h5-ui/src/pages/hotel/customer/room-confirm.vue` | 入口 | 扫码验证房间、房间卡片、开始点餐 | | 点餐菜单 | `forge-h5-ui/src/pages/hotel/customer/menu.vue` | Tab1 | 分类导航、菜品列表、搜索、购物车浮层 | | 菜品详情 | `forge-h5-ui/src/pages/hotel/customer/dish-detail.vue` | 子页 | 大图、规格选择、加料、备注、加入购物车 | | 购物车 | `forge-h5-ui/src/pages/hotel/customer/cart.vue` | Tab3 | 商品列表、数量控制、备注、费用汇总、结算 | | 确认下单 | `forge-h5-ui/src/pages/hotel/customer/order-confirm.vue` | 子页 | 配送信息、送达时间、明细、提交订单(已移除硬编码支付方式) | | 支付确认 | `forge-h5-ui/src/pages/hotel/customer/pay.vue` | 子页 | 支付宝 H5 WAP Pay + 轮询 + 主动查询兜底 + 倒计时 | | 订单状态 | `forge-h5-ui/src/pages/hotel/customer/order-status.vue` | Tab2 | 进度条、状态卡片、10秒轮询、自定义退单弹窗 | | 历史订单 | `forge-h5-ui/src/pages/hotel/customer/orders.vue` | Tab2 | 订单卡片列表、分页加载、状态标签、待支付"去支付"按钮 | ### 待开发 | 页面 | 路径 | 说明 | 源框架参考 | |------|------|------|-----------| | 酒店配置 | `views/hotel/config.vue` | 单例配置表单(暂缓) | `HotelConfigManagement.vue` | | ~~订单看板~~ | ~~`views/hotel/orderDashboard.vue`~~ | ~~已集成到 order.vue 工具栏,无需单独页面~~ | 无直接参考 | --- ## 八、关键决策记录 ### 8.1 暂缓开发项 | 模块 | 原因 | 待讨论点 | |------|------|--------| | hotelconfig(酒店基础配置) | 暂不需要 | 配送费规则(按距离/区域/固定?)、预计配送时长(固定/动态?) | ### 8.2 技术决策 | 决策 | 说明 | |------|------| | 规格组统一命名 | 源框架同时存在 `hotel_dish_spec` 和 `hotel_dish_spec_group`,Forge 统一使用 `hotel_dish_spec_group` | | 营业时段时间选择 | 使用下拉选择(09:00~23:30,每 30 分钟一档),而非时间选择器 | | 餐段类型 | 仅保留早餐/午餐/晚餐三种,移除夜宵 | | 前端组件规范 | 统一使用 AiCrudPage 配置化页面,保持分页/筛选/操作列格式一致 | | 订单状态值 | 使用数字 0~10 连续编号(0=待支付, 1~9 原有状态, 10=超时取消),非英文字符串常量 | | 订单金额 | 使用 `BigDecimal` + 元(`DECIMAL(10,2)`),与 dish 模块保持一致 | | 订单模块包结构 | 独立 `order/` 子包,与已有 hotel 代码分离 | | 看板统计集成 | 订单看板统计集成到 AiCrudPage 工具栏 `#toolbar-start` slot,不单独建页面 | | H5 顾客端框架 | Vue 3 `