Ver código fonte

智能柜项目提交

skyline 4 meses atrás
pai
commit
b1773f887a

BIN
current_state.png


BIN
dashboard_screenshot.png


BIN
dashboard_verification.png


BIN
devtools_opened.png


BIN
final_menu_state.png


+ 76 - 76
haha-miniapp/src/main/java/com/haha/miniapp/controller/CallbackController.java

@@ -23,9 +23,9 @@ import java.util.Map;
 
 /**
  * 哈哈平台回调通知接口
- * 
+ *
  * 接收哈哈平台推送的各类通知,分为两类回调地址:
- * 
+ *
  * 1. 消息回调地址 (/callback/haha/message)
  *    - DEVICE_STATUS: 开关门状态通知
  *    - ONLINE_STATUS: 设备在线状态通知
@@ -33,11 +33,11 @@ import java.util.Map;
  *    - CLIENT_NEW_PRODUCT: 新品审核结果回调
  *    - MERGE_PRODUCT: 商品合并结果通知
  *    - ORC_RESULT: AI识别结果通知(最重要)
- * 
+ *
  * 2. 订单回调地址 (/callback/haha/order)
  *    - 哈哈平台生成订单后推送的订单信息
  *    - 包含订单号、设备号、用户ID、订单明细、金额等
- * 
+ *
  * 注意:
  * - 所有通知都包含 sign 字段用于验证
  * - 必须返回 "success" 字符串表示接收成功
@@ -51,16 +51,16 @@ public class CallbackController {
 
     @Autowired
     private OrderService orderService;
-    
+
     @Value("${haha.api.app-secret}")
     private String appSecret;
 
     /**
      * 消息回调通知统一入口
-     * 
+     *
      * 接收哈哈平台推送的所有类型通知,通过 notify_type 区分具体类型
      * 支持 application/json 和 application/x-www-form-urlencoded 两种格式
-     * 
+     *
      * @param request HTTP请求对象
      * @param requestParams form表单参数(用于application/x-www-form-urlencoded)
      * @return 响应结果,必须返回 "success" 字符串
@@ -72,21 +72,21 @@ public class CallbackController {
         try {
             // 解析请求参数(兼容JSON和表单两种格式)
             Map<String, Object> params = parseRequestParams(request, requestParams);
-            
+
             // 记录回调日志
             log.info("收到消息回调通知: {}", JSON.toJSONString(params));
-            
+
             // 1. 验证签名(如果需要)
             // validateSign(params);
-            
+
             // 2. 获取通知类型
             String notifyType = (String) params.get("notify_type");
-            
+
             if (notifyType == null || notifyType.isEmpty()) {
                 log.warn("消息回调缺少 notify_type 参数");
                 return "success";
             }
-            
+
             // 3. 根据通知类型分发处理
             switch (notifyType) {
                 case "DEVICE_STATUS":
@@ -110,10 +110,10 @@ public class CallbackController {
                 default:
                     log.warn("未知的消息通知类型: {}", notifyType);
             }
-            
+
             // 4. 返回成功响应(必须返回 "success" 字符串)
             return "success";
-            
+
         } catch (Exception e) {
             log.error("处理消息回调通知失败", e);
             // 即使处理失败,也返回成功,避免重复推送
@@ -123,13 +123,13 @@ public class CallbackController {
 
     /**
      * 处理开关门状态通知 (DEVICE_STATUS)
-     * 
+     *
      * status取值:
      * - 1=ERROR(开门失败)
      * - 2=OPENED(门已开)
      * - 3=CLOSED(门已关)
      * - 4=ANOTHER(设备繁忙)
-     * 
+     *
      * @param params 通知参数
      */
     private void handleDeviceStatus(Map<String, Object> params) {
@@ -139,10 +139,10 @@ public class CallbackController {
             String status = (String) params.get("status");
             String openType = (String) params.get("open_type");
             String outUserId = (String) params.get("out_user_id");
-            
-            log.info("开关门状态通知 - 设备: {}, 状态: {}, 类型: {}, 用户: {}", 
+
+            log.info("开关门状态通知 - 设备: {}, 状态: {}, 类型: {}, 用户: {}",
                 deviceId, status, openType, outUserId);
-            
+
             // 可以根据业务需要处理不同状态
             switch (status) {
                 case "2": // OPENED
@@ -158,7 +158,7 @@ public class CallbackController {
                     log.warn("设备 {} 繁忙", deviceId);
                     break;
             }
-            
+
         } catch (Exception e) {
             log.error("处理开关门状态通知失败", e);
         }
@@ -166,19 +166,19 @@ public class CallbackController {
 
     /**
      * 处理设备在线状态通知 (ONLINE_STATUS)
-     * 
+     *
      * @param params 通知参数
      */
     private void handleOnlineStatus(Map<String, Object> params) {
         try {
             String deviceId = (String) params.get("device_id");
             Integer isOnline = parseInteger(params.get("is_online"));
-            
-            log.info("设备在线状态通知 - 设备: {}, 在线状态: {}", 
+
+            log.info("设备在线状态通知 - 设备: {}, 在线状态: {}",
                 deviceId, isOnline != null && isOnline == 1 ? "在线" : "离线");
-            
+
             // 可以在这里更新设备在线状态到数据库
-            
+
         } catch (Exception e) {
             log.error("处理设备在线状态通知失败", e);
         }
@@ -186,16 +186,16 @@ public class CallbackController {
 
     /**
      * 处理音量调节结果通知 (VOICE_RESULT)
-     * 
+     *
      * @param params 通知参数
      */
     private void handleVoiceResult(Map<String, Object> params) {
         try {
             String deviceId = (String) params.get("device_id");
             Integer voice = parseInteger(params.get("voice"));
-            
+
             log.info("音量调节结果通知 - 设备: {}, 音量值: {}", deviceId, voice);
-            
+
         } catch (Exception e) {
             log.error("处理音量调节结果通知失败", e);
         }
@@ -203,12 +203,12 @@ public class CallbackController {
 
     /**
      * 处理新品审核结果回调 (CLIENT_NEW_PRODUCT)
-     * 
+     *
      * status取值:
      * - 1=已通过
      * - 2=已拒绝
      * - 3=已上架
-     * 
+     *
      * @param params 通知参数
      */
     private void handleNewProductAudit(Map<String, Object> params) {
@@ -218,13 +218,13 @@ public class CallbackController {
             String name = (String) params.get("name");
             String code = (String) params.get("code");
             String rejectReason = (String) params.get("reject_reason");
-            
+
             log.info("新品审核结果 - ID: {}, 商品名: {}, 状态: {}, code: {}", id, name, status, code);
-            
+
             if (status != null && status == 2) {
                 log.warn("新品 {} 被拒绝,原因: {}", name, rejectReason);
             }
-            
+
         } catch (Exception e) {
             log.error("处理新品审核结果通知失败", e);
         }
@@ -232,17 +232,17 @@ public class CallbackController {
 
     /**
      * 处理商品合并结果通知 (MERGE_PRODUCT)
-     * 
+     *
      * @param params 通知参数
      */
     private void handleMergeProduct(Map<String, Object> params) {
         try {
             Object listObj = params.get("list");
-            
+
             if (listObj instanceof JSONArray) {
                 JSONArray list = (JSONArray) listObj;
                 log.info("商品合并结果通知 - 合并数量: {}", list.size());
-                
+
                 for (Object item : list) {
                     if (item instanceof JSONObject) {
                         JSONObject merge = (JSONObject) item;
@@ -252,7 +252,7 @@ public class CallbackController {
                     }
                 }
             }
-            
+
         } catch (Exception e) {
             log.error("处理商品合并结果通知失败", e);
         }
@@ -260,66 +260,66 @@ public class CallbackController {
 
     /**
      * 处理AI识别结果通知 (ORC_RESULT) - 最重要的回调
-     * 
+     *
      * 用户关门后,AI识别完成,哈哈平台推送识别结果
-     * 
+     *
      * @param params 通知参数
      */
     private void handleOrcResult(Map<String, Object> params) {
         try {
             String activityId = (String) params.get("activity_id");
             String deviceId = (String) params.get("device_id");
-            String outUserId = (String) params.get("out_user_id");
-            
+            String userId = (String) params.get("out_user_id");
+
             // 安全转换 nobuy 字段(兼容字符串和整型)
             Integer nobuy = parseInteger(params.get("nobuy"));
-            
+
             // 解析识别结果
             String resultStr = (String) params.get("result");
             String skuListStr = (String) params.get("sku_list");
             String resourceInfoStr = (String) params.get("resource_info");
-            
-            log.info("AI识别结果通知 - 设备: {}, 活动: {}, 是否消费: {}", 
+
+            log.info("AI识别结果通知 - 设备: {}, 活动: {}, 是否消费: {}",
                 deviceId, activityId, nobuy != null && nobuy == 1 ? "无消费" : "有消费");
-            
+
             if (nobuy != null && nobuy == 1) {
                 log.info("用户打开柜门但未消费,无需处理");
                 return;
             }
-            
+
             // 解析result字段
             if (resultStr != null && !resultStr.isEmpty()) {
                 JSONObject result = JSON.parseObject(resultStr);
                 String type = result.getString("type"); // IN或OUT
                 JSONArray data = result.getJSONArray("data");
                 JSONArray excepts = result.getJSONArray("excepts");
-                
+
                 log.info("识别类型: {}, 数据: {}", type, data != null ? data.size() : 0);
-                
+
                 // 检查是否有异常
                 if (excepts != null && !excepts.isEmpty()) {
                     log.warn("识别结果包含异常: {}", excepts.toJSONString());
                 }
             }
-            
+
             // 解析sku_list
             if (skuListStr != null && !skuListStr.isEmpty()) {
                 JSONArray skuList = JSON.parseArray(skuListStr);
                 log.info("商品数量: {}", skuList != null ? skuList.size() : 0);
             }
-            
+
             // 解析resource_info获取视频URL
             if (resourceInfoStr != null && !resourceInfoStr.isEmpty()) {
                 JSONObject resourceInfo = JSON.parseObject(resourceInfoStr);
                 String videoUrl = resourceInfo.getString("video_url");
                 log.info("视频URL: {}", videoUrl);
             }
-            
+
             // TODO: 根据识别结果进行后续处理
             // 1. 计算订单金额
             // 2. 生成订单记录
             // 3. 触发支付流程
-            
+
         } catch (Exception e) {
             log.error("处理AI识别结果通知失败", e);
         }
@@ -327,11 +327,11 @@ public class CallbackController {
 
     /**
      * 订单回调通知接口
-     * 
+     *
      * 当AI识别完成并生成订单后,哈哈平台会推送订单信息到此接口
      * 这是独立于消息回调的订单回调接口
      * 支持 application/json 和 application/x-www-form-urlencoded 两种格式
-     * 
+     *
      * @param request HTTP请求对象
      * @param requestParams form表单参数(用于application/x-www-form-urlencoded)
      * @return 响应结果,必须返回 "success" 字符串
@@ -343,13 +343,13 @@ public class CallbackController {
         try {
             // 解析请求参数(兼容JSON和表单两种格式)
             Map<String, Object> params = parseRequestParams(request, requestParams);
-            
+
             // 记录回调日志
             log.info("收到订单回调通知: {}", JSON.toJSONString(params));
-            
+
             // 1. 验证签名(如果需要)
             // validateSign(params);
-            
+
             // 2. 提取订单信息
             String orderId = (String) params.get("order_id");
             String deviceId = (String) params.get("device_id");
@@ -360,10 +360,10 @@ public class CallbackController {
             String from = (String) params.get("from");
             Object orderMoney = params.get("order_money");
             Object createTime = params.get("create_time");
-            
+
             log.info("订单信息 - 订单号: {}, 设备: {}, 活动: {}, 用户: {}, 金额: {}",
                 orderId, deviceId, activityId, userId, orderMoney);
-            
+
             // 3. 查找本地订单记录
             Order localOrder = orderService.lambdaQuery()
                 .eq(Order::getUserId, Long.parseLong(userId))
@@ -372,41 +372,41 @@ public class CallbackController {
                 .orderByDesc(Order::getCreateTime)
                 .last("LIMIT 1")
                 .one();
-            
+
             if (localOrder == null) {
                 log.warn("未找到对应的本地订单记录,用户: {}, 设备: {}", userId, deviceId);
                 return "success";
             }
-            
+
             // 4. 更新本地订单信息
             localOrder.setOrderNo(orderId);
             localOrder.setActivityId(activityId);
-            
+
             // 将订单明细存储到 items 字段(JSON格式)
             if (orderDetail != null) {
                 localOrder.setItems(orderDetail);
             }
-            
+
             // 设置订单金额
             if (orderMoney != null) {
                 localOrder.setTotalAmount(Double.parseDouble(orderMoney.toString()));
             }
-            
+
             boolean updated = orderService.updateById(localOrder);
             if (updated) {
                 log.info("订单信息更新成功: {}", orderId);
             } else {
                 log.error("订单信息更新失败: {}", orderId);
             }
-            
+
             // 5. TODO: 根据业务需要进行后续处理
             // - 触发支付流程
             // - 发送通知给用户
             // - 更新库存等
-            
+
             // 6. 返回成功响应
             return "success";
-            
+
         } catch (Exception e) {
             log.error("处理订单回调通知失败", e);
             // 即使处理失败,也返回成功,避免重复推送
@@ -416,17 +416,17 @@ public class CallbackController {
 
     /**
      * 解析请求参数,支持 JSON 和 form-urlencoded 两种格式
-     * 
+     *
      * @param request HTTP请求对象
      * @param requestParams form表单参数
      * @return 参数Map
      */
     private Map<String, Object> parseRequestParams(HttpServletRequest request, Map<String, String> requestParams) {
         Map<String, Object> params = new HashMap<>();
-        
+
         String contentType = request.getContentType();
         log.debug("请求Content-Type: {}", contentType);
-        
+
         try {
             // 判断 Content-Type
             if (contentType != null && contentType.toLowerCase().contains("application/json")) {
@@ -453,13 +453,13 @@ public class CallbackController {
         } catch (Exception e) {
             log.error("解析请求参数失败", e);
         }
-        
+
         return params;
     }
 
     /**
      * 安全转换为整型,兼容字符串和整型
-     * 
+     *
      * @param value 原始值
      * @return 整型值,如果转换失败返回null
      */
@@ -467,7 +467,7 @@ public class CallbackController {
         if (value == null) {
             return null;
         }
-        
+
         try {
             if (value instanceof Integer) {
                 return (Integer) value;
@@ -483,13 +483,13 @@ public class CallbackController {
         } catch (NumberFormatException e) {
             log.warn("无法转换为整型: {}", value);
         }
-        
+
         return null;
     }
 
     /**
      * 验证签名
-     * 
+     *
      * @param params 回调参数
      * @throws Exception 签名验证失败
      */
@@ -498,7 +498,7 @@ public class CallbackController {
         if (receivedSign == null || receivedSign.isEmpty()) {
             throw new Exception("签名参数为空");
         }
-        
+
         // TODO: 实现签名验证逻辑
         // 1. 提取所有参数(除sign外)
         // 2. 按字典序排序

BIN
menu_after_click.png


BIN
menu_after_hover.png


BIN
menu_api_response.png


BIN
menu_current_state.png


BIN
menu_diagnostic_report.png


BIN
menu_expanded.png


BIN
menu_full_page.png


BIN
sidebar_detail.png


BIN
sidebar_full_check.png


BIN
sidebar_narrow.png