|
|
@@ -0,0 +1,91 @@
|
|
|
+# CLAUDE.md — 哈哈智能零售系统
|
|
|
+
|
|
|
+## 项目概览
|
|
|
+
|
|
|
+基于 Spring Boot 的 AI 智能视觉售卖机系统,包含用户端小程序、管理后台、硬件通信等模块。
|
|
|
+
|
|
|
+### 技术栈
|
|
|
+- **后端**: Java 21, Spring Boot 4.0.3, MyBatis-Plus 3.5.16
|
|
|
+- **前端**: Vue 3 + Element Plus (admin-web), uni-app (mp)
|
|
|
+- **数据库**: MySQL, Redis
|
|
|
+- **服务端口**: miniapp 7077, admin 7070
|
|
|
+- **支付**: 微信支付 JSAPI + 支付分 (Pay Score)
|
|
|
+
|
|
|
+### 模块结构
|
|
|
+```
|
|
|
+haha-parent
|
|
|
+├── haha-common — 公共工具、枚举、VO
|
|
|
+├── haha-entity — 实体类、DTO
|
|
|
+├── haha-mapper — MyBatis Mapper
|
|
|
+├── haha-service — 核心业务逻辑(回调处理、支付、订单、库存等)
|
|
|
+├── haha-miniapp — 用户端小程序后端 (port 7077)
|
|
|
+├── haha-admin — 管理后台后端 (port 7070)
|
|
|
+├── haha-sdk — 哈哈平台 SDK (API调用、Token管理)
|
|
|
+├── qdb-sdk — 千岛板 SDK
|
|
|
+├── haha-mp — 用户端小程序前端 (uni-app)
|
|
|
+├── haha-admin-web — 管理后台前端 (Vue 3)
|
|
|
+└── haha-admin-mp — 管理端小程序
|
|
|
+```
|
|
|
+
|
|
|
+## 哈哈平台回调流程
|
|
|
+
|
|
|
+### 两类回调
|
|
|
+| 回调 | 路径 | 作用 |
|
|
|
+|------|------|------|
|
|
|
+| ORC_RESULT | `/api/callback/haha/message` (notify_type=ORC_RESULT) | AI 识别结果,触发订单创建 |
|
|
|
+| ORDER | `/api/callback/haha/order` | 设备端报价,写入金额 |
|
|
|
+
|
|
|
+### 订单创建时序
|
|
|
+```
|
|
|
+1. 用户开门 → preCreatePayScoreOrder (微信支付分预授权) → 存 Redis (TTL 10min)
|
|
|
+2. AI识别完成 → ORC_RESULT 回调 → 创建订单 + 关联支付分 → 清理Redis
|
|
|
+3. 设备报价 → ORDER 回调 → validateSign → 写入 totalAmount/paidAmount
|
|
|
+4. 消息推送 → 用户确认付款
|
|
|
+```
|
|
|
+
|
|
|
+### 签名验证 (重要!)
|
|
|
+- 哈哈平台使用 **MD5(signStr + ticket)** 签名
|
|
|
+- 签名原文: 参数按 key 排序,值 URL 编码后 `key=value&...` 拼接,末尾直接拼接 ticket
|
|
|
+- ⚠️ **不能使用 Spring `@RequestParam` 解析后的参数重建签名!** Spring 会 URL-decode,Java `URLEncoder` 重新 encode 的结果与 PHP 原始 `urlencode` 不一致
|
|
|
+- **必须从原始 request body 构建签名** → `buildSignContentFromRawBody()`
|
|
|
+- 见 `HahaCallbackServiceImpl.java:620` 的 `validateSign(params, rawBody)` 方法
|
|
|
+
|
|
|
+### 支付分关键限制
|
|
|
+- 同一实名用户 **进行中订单 ≤ 3 笔** (微信硬限制)
|
|
|
+- 超过 3 笔 → 用户无法扫码开门 (错误: "同一实名身份下进行中订单过多")
|
|
|
+- 分级清理策略 (见 `PayScoreServiceImpl.cancelStalePayScoreOrdersAndCount`):
|
|
|
+ 1. 自动补扣: 有金额的待支付订单 (>1min)
|
|
|
+ 2. 取消 CREATED: 用户从未确认
|
|
|
+ 3. 清理超时孤儿: DOING/USER_PAYING + 无金额 + >30min
|
|
|
+ 4. Redis 追踪清理
|
|
|
+
|
|
|
+### 支付分完结金额校验
|
|
|
+- 微信要求 `total_amount == sum(post_payments[].amount)` 严格相等
|
|
|
+- DB 中单价保留 2 位小数,乘数量后求和可能产生 **1 分钱差额**
|
|
|
+- 解决方案: `buildPostPayments(orderId, totalAmount)` 自动平账到末项
|
|
|
+
|
|
|
+### 日志路径
|
|
|
+- miniapp: `./logs/haha-miniapp/haha-miniapp.log`
|
|
|
+- admin: `./logs/haha-admin/haha-admin.log`
|
|
|
+- JVM 工作目录 `/home/kym/application` (服务器)
|
|
|
+- prod 环境: logback-spring.xml 同时输出 CONSOLE + FILE
|
|
|
+
|
|
|
+## 关键文件索引
|
|
|
+| 文件 | 功能 |
|
|
|
+|------|------|
|
|
|
+| `HahaCallbackServiceImpl.java` | 回调处理: 签名验证、订单创建、支付分完结 |
|
|
|
+| `PayScoreServiceImpl.java` | 支付分: 预授权、创建、完结、取消、限额清理 |
|
|
|
+| `OrderServiceImpl.java` | 订单: CRUD、支付分集成、库存扣减 |
|
|
|
+| `CallbackController.java` | 回调入口 (miniapp 7077) |
|
|
|
+| `OrderController.java` | 管理后台订单接口 (admin 7070) |
|
|
|
+| `RequestParseUtil.java` | 请求解析 (JSON/XML/Form) |
|
|
|
+| `HahaClient.java` | 哈哈平台 SDK (Token/Ticket管理) |
|
|
|
+
|
|
|
+## 常见故障排查
|
|
|
+| 现象 | 原因 | 解决方案 |
|
|
|
+|------|------|---------|
|
|
|
+| 订单有商品无金额 | ORDER 回调签名失败 | 检查签名日志,修复后用 SQL 补齐 |
|
|
|
+| 支付分补扣失败 PARAM_ERROR | post_payments 总额 ≠ total_amount | 已修复自动平账 |
|
|
|
+| 支付分补扣失败 REVOKED | 新支付分订单创建导致旧单被撤销 | 新流程自动清理+前端拦截 |
|
|
|
+| 用户无法开门 | 进行中订单 ≥ 3 笔 | `cancelStalePayScoreOrdersAndCount` 自动清理 |
|
|
|
+| 日志文件找不到 | 路径配错或权限问题 | 检查 `logging.file.path` 和 JVM 工作目录 |
|