# 设备与门店模块业务说明 > 本文档描述设备管理、门店管理、库存管理及设备回调链路。 > 帮助开发人员快速理解"为什么这样设计"以及各环节的特殊处理方式。 --- ## 一、设备管理 ### 1.1 Device 实体 | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | deviceId | String | 设备SN号(唯一标识) | | shopId | Long | 所属门店ID | | name | String | 设备名称 | | authToken | String | 设备认证Token | | status | Integer | 设备状态 | | doorStatus | String | 门状态:ERROR / OPENED / CLOSED / ANOTHER(设备繁忙) | | currentInventoryHash | String | 当前库存哈希(用于同步判断) | | createTime / updateTime | LocalDateTime | 时间戳 | **非DB字段**(`@TableField(exist = false)`):shopName, address, deviceTypeLabel, statusLabel, statusColor, isOnline, temperature, volume, doorCount, layerCount, hasScreen, totalSales, todaySales, orderCount, lastOnlineTime ### 1.2 门状态枚举 (`DeviceDoorStatus`) | code | 枚举值 | 说明 | |------|--------|------| | ERROR | 开门失败 | 远程开门请求失败 | | OPENED | 门已开 | 门处于打开状态 | | CLOSED | 门已关 | 门处于关闭状态 | | ANOTHER | 设备繁忙 | 设备正忙,无法开门 | #### 为什么门状态用字符串而非数字编码? 门状态直接来自哈哈平台设备端的回调,设备端使用字符串状态码(如 "1"=ERROR, "2"=OPENED, "3"=CLOSED, "4"=ANOTHER)。为避免数字编码与数据库值之间的映射混乱,`DeviceDoorStatus` 枚举在数据库中存储英文状态字符串(ERROR/OPENED/CLOSED/ANOTHER),并在 `convertToDbValue()` 方法中处理原始数字码到字符串的转换。这种设计使得数据库中的值自解释,排查问题时一目了然。 ### 1.3 设备服务核心方法 (`DeviceService`) | 方法 | 说明 | |------|------| | getPage() | 分页查询设备列表(支持门店/状态筛选) | | getDetailById() | 设备详情(含门店名、状态标签填充) | | getStatistics() | 设备统计数据 | | openDoor() | 远程开门 | | scanCodeOpenDoor() | 扫码开门业务(含支付分校验) | | setTemperature() | 设置温度 | | setVolume() | 设置音量 | | getNearbyDevices() | 附近设备查询(经纬度+距离) | | getDeviceBySn() | 通过SN号查询设备 | | updateDeviceStatus() | 更新设备状态 | | updateInventoryHash() | 更新库存哈希 | --- ## 二、设备回调处理 (`HahaCallbackService`) #### 什么是设备回调? 哈哈平台(智能售卖机设备平台)采用回调机制主动推送设备事件。我们的服务端作为回调接收方,在 `CallbackController` 中接收并分发处理。回调类型包括设备状态变更、AI识别结果、订单信息等。 **为什么用回调而非轮询?** - 实时性:设备事件立即推送,无需等待轮询周期 - 高效:只有事件发生时才产生网络请求,节省资源 - 可靠:回调失败可重试,配合签名验证保证安全 ### 2.1 回调消息类型 | 类型 | 方法 | 说明 | |------|------|------| | DEVICE_STATUS | handleDeviceStatus() | 开关门状态通知 | | ONLINE_STATUS | handleOnlineStatus() | 设备在线/离线通知 | | VOICE_RESULT | handleVoiceResult() | 音量调节结果 | | CLIENT_NEW_PRODUCT | handleNewProductAudit() | 新品审核结果 | | MERGE_PRODUCT | handleMergeProduct() | 商品合并结果 | | ORC_RESULT | handleOrcResult() | AI识别结果通知 | | 订单回调 | handleOrderCallback() | 设备端订单信息回调 | ### 2.2 核心回调流程 #### ORC_RESULT(AI识别回调) ``` 设备AI识别完成 ↓ 解析 sku_list: [{code, quantity}] ↓ 创建/查找订单 createOrderFromRecognition() - 幂等:通过 activityId 防重复 - 订单金额初始化为0(等待设备端回调) ↓ 解析视频URL等资源信息 ↓ 创建 DoorRecord(doorStatus=CLOSED) ``` #### 订单回调 ``` 设备端计算好订单金额和商品明细后回调 ↓ 查找或创建本地订单 ↓ updateOrderFromCallback() - 写入 orderNo, totalAmount, items - 初始化 discountAmount=0, paidAmount=totalAmount ↓ saveOrderGoods() — 保存订单商品明细 ↓ processCouponDiscount() — 自动优惠券扣减 ↓ processPayScorePayment() — 支付分扣费 ``` --- ## 三、开关门记录 (DoorRecord) ### 3.1 实体字段 | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | activityId | String | 哈哈平台活动ID | | deviceId | String | 设备ID | | userId | Long | 用户ID | | doorIndex | String | 门索引(A/B/C/D) | | openType | String | 开门类型:IN-上货,OUT-消费 | | doorStatus | String | 门状态:OPENED-已开,CLOSED-已关 | | nobuy | Integer | 是否无消费:0-有消费,1-无消费 | | orderId | Long | 关联订单ID(有消费时) | | openTime | LocalDateTime | 开门时间 | | closeTime | LocalDateTime | 关门时间 | | duration | Integer | 持续时长(秒) | | source | String | 来源:MINIAPP / ADMIN | | remark | String | 备注 | ### 3.2 开门类型 (`OpenType`) | code | 说明 | |------|------| | IN | 上货开门(运营人员补货) | | OUT | 消费开门(用户购物) | --- ## 四、门店管理 ### 4.1 Shop 实体 | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | shopCode | String | 门店编码(唯一标识) | | name | String | 门店名称 | | address | String | 门店地址 | | province / city / district | String | 省市区 | | longitude / latitude | Double | 经纬度 | | contactName / contactPhone | String | 联系人/电话 | | businessHours | String | 营业时间 | | status | Integer | 状态:0-禁用 1-启用 | | remark | String | 备注 | **非DB字段**:deviceCount(设备总数), onlineCount(在线设备数), statusLabel, statusColor ### 4.2 门店服务核心方法 (`ShopService`) | 方法 | 说明 | |------|------| | getPage() | 分页查询门店 | | getDetailById() | 门店详情(含设备数/在线数) | | getStatistics() | 门店统计 | | getNearbyShops() | 附近门店查询(小程序端) | ### 4.3 门店补货员 (ShopReplenisher) 关联门店和补货人员,用于补货权限管理。 --- ## 五、库存管理 ### 5.1 DeviceInventory 实体(设备商品库存) | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | deviceId | String | 设备ID(SN号) | | productId | Long | 商品ID(本地) | | productCode | String | 商品编码(哈哈平台code) | | productName | String | 商品名称(冗余) | | stock | Integer | 当前库存数量 | | shelfNum | Integer | 货架层号 | | position | String | 货道位置(left/right) | | warningThreshold | Integer | 库存预警阈值 | | lastRestockTime | LocalDateTime | 最后补货时间 | ### 5.2 库存服务 (`DeviceInventoryService`) | 方法 | 说明 | |------|------| | getInventoryByDevice() | 查询设备库存列表 | | syncInventory() | 同步设备库存(从设备端获取最新数据) | | deductStock() | 扣减库存(订单完成后) | | checkLowStock() | 低库存预警检查 | ### 5.3 库存同步流程 ``` 设备端上报库存变更 ↓ HahaCallbackService 接收通知 ↓ 比对 currentInventoryHash ↓ 如不一致 → 调用哈哈SDK获取最新库存 ↓ 更新 DeviceInventory 记录 ↓ 更新 currentInventoryHash ↓ 检查低库存 → 触发告警 ``` #### 库存哈希机制的设计考量 `currentInventoryHash` 是设备当前库存的哈希摘要。每次设备端回调库存变更时,先比对哈希值: - 哈希一致 → 库存未变化,跳过同步,减少不必要的SDK调用 - 哈希不一致 → 库存有变化,拉取最新数据并更新 这种设计避免了频繁全量同步的性能开销,只在库存确实变化时才触发同步。 ### 5.4 补货记录 (StockRecord / StockRecordItem) | 实体 | 说明 | |------|------| | StockRecord | 补货记录主表(操作人、设备、时间) | | StockRecordItem | 补货明细(商品、数量变化) | --- ## 六、设备告警体系 ### 6.1 DeviceAlertRecord 实体 | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | deviceId | String | 设备ID | | alertType | String | 告警类型 | | alertLevel | Integer | 告警级别 | | title | String | 告警标题 | | content | String | 告警内容 | | status | Integer | 处理状态 | ### 6.2 告警类型 (`DeviceAlertType`) | code | 说明 | |------|------| | OFFLINE | 设备离线 | | LOW_STOCK | 低库存 | | DOOR_ERROR | 开门异常 | ### 6.3 告警通知 告警通过企业微信 Webhook 推送,配置在 `haha-service/.../notify/` 中。 --- ## 七、商品管理 ### 7.1 Product 实体 | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 雪花算法主键 | | productId | String | 哈哈平台商品ID | | code | String | 商品编码(哈哈平台code) | | barcode | String | 商品条码 | | name | String | 商品名称 | | type | String | 商品分类 | | pic | String | 商品图片URL | | retailPrice | Double | 零售价 | | costPrice | Double | 成本价 | | applyStatus | String | 适用设备:全部柜/静态柜/动态柜 | | syncStatus | Integer | 同步状态:0-未同步 1-同步中 2-已同步 3-同步失败 | ### 7.2 商品同步 商品数据从哈哈平台(SDK)同步到本地,`DataSyncServiceImpl` 处理全量/增量同步。 --- ## 八、核心代码文件索引 | 文件 | 职责 | |------|------| | `haha-entity/.../Device.java` | 设备实体 | | `haha-entity/.../Shop.java` | 门店实体 | | `haha-entity/.../Product.java` | 商品实体 | | `haha-entity/.../DoorRecord.java` | 开关门记录 | | `haha-entity/.../DeviceInventory.java` | 设备库存 | | `haha-entity/.../StockRecord.java` | 补货记录 | | `haha-entity/.../DeviceAlertRecord.java` | 设备告警记录 | | `haha-service/.../DeviceServiceImpl.java` | 设备服务 | | `haha-service/.../ShopServiceImpl.java` | 门店服务 | | `haha-service/.../ProductServiceImpl.java` | 商品服务 | | `haha-service/.../DoorRecordServiceImpl.java` | 开关门记录服务 | | `haha-service/.../DeviceInventoryServiceImpl.java` | 库存服务 | | `haha-service/.../DeviceAlertServiceImpl.java` | 告警服务 | | `haha-service/.../HahaCallbackServiceImpl.java` | 设备回调处理 | | `haha-service/.../DataSyncServiceImpl.java` | 数据同步服务 | | `haha-admin/.../DeviceController.java` | 运营平台-设备API | | `haha-admin/.../ShopController.java` | 运营平台-门店API | | `haha-admin/.../InventoryController.java` | 运营平台-库存API | | `haha-admin/.../DeviceAlertController.java` | 运营平台-告警API | | `haha-miniapp/.../DeviceController.java` | 小程序-设备API | | `haha-common/.../enums/DeviceDoorStatus.java` | 门状态枚举 | | `haha-common/.../enums/DeviceAlertType.java` | 告警类型枚举 | | `haha-common/.../enums/DeviceOnlineStatus.java` | 在线状态枚举 | | `haha-common/.../constant/DeviceConstants.java` | 设备常量 |