Forráskód Böngészése

完善 BootEventHandler 设备重启对账逻辑,totalSeconds 改为 Long

- BootEventHandler 注入 AwoaraService 和 OrderSettlementService
- 设备启动时对未支付订单逐个查询设备状态,已关闭则结算,未找到则标记待定时对账
- UserLoginEventHandler 补充注释说明暂不支持机器端登录
- WashOrder.totalSeconds 由 Integer 改为 Long,同步更新 StatServiceImpl

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 1 napja
szülő
commit
6ae6a8fb16

+ 1 - 1
car-wash-entity/src/main/java/com/kym/entity/WashOrder.java

@@ -145,7 +145,7 @@ public class WashOrder extends BaseEntity {
     /**
      * 洗车总时长(秒)
      */
-    private Integer totalSeconds;
+    private Long totalSeconds;
 
     /**
      * 优惠方式:RechargeRights-充值权益 Coupon-优惠券

+ 71 - 15
car-wash-service/src/main/java/com/kym/service/awoara/event/handle/BootEventHandler.java

@@ -4,11 +4,12 @@ import com.kym.entity.WashDevice;
 import com.kym.entity.WashOrder;
 import com.kym.entity.awoara.DeviceStateObject;
 import com.kym.entity.awoara.MessageBody;
+import com.kym.entity.awoara.OrderInfo;
+import com.kym.service.OrderSettlementService;
 import com.kym.service.WashDeviceService;
 import com.kym.service.WashOrderService;
+import com.kym.service.awoara.AwoaraService;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 设备启动事件处理
@@ -16,42 +17,97 @@ import org.springframework.transaction.annotation.Transactional;
  * @author skyline
  */
 @Slf4j
-@Component
 public class BootEventHandler implements AwoaraEventHandler<DeviceStateObject> {
 
     private final WashDeviceService washDeviceService;
-
     private final WashOrderService washOrderService;
+    private final AwoaraService awoaraService;
+    private final OrderSettlementService orderSettlementService;
 
-    public BootEventHandler(WashDeviceService washDeviceService, WashOrderService washOrderService) {
+    public BootEventHandler(WashDeviceService washDeviceService,
+                            WashOrderService washOrderService,
+                            AwoaraService awoaraService,
+                            OrderSettlementService orderSettlementService) {
         this.washDeviceService = washDeviceService;
         this.washOrderService = washOrderService;
+        this.awoaraService = awoaraService;
+        this.orderSettlementService = orderSettlementService;
     }
 
     @Override
-    @Transactional
     public void handle(MessageBody<DeviceStateObject> message) {
-        log.info(message.toString());
-        log.info("BootEventHandler");
-        // 获取设备信息 从topic中获取
-        log.debug("topic:{}", message.getTopic());
+        log.info("BootEventHandler: {}", message);
+
         var topic = message.getTopic().split("/");
         var productKey = topic[1];
         var deviceName = topic[2];
-        log.debug("productKey:{},deviceName:{}", productKey, deviceName);
 
-        var device = washDeviceService.lambdaQuery().eq(WashDevice::getProductKey, productKey).eq(WashDevice::getDeviceName, deviceName).one();
+        var device = washDeviceService.lambdaQuery()
+                .eq(WashDevice::getProductKey, productKey)
+                .eq(WashDevice::getDeviceName, deviceName)
+                .one();
+
+        if (device == null) {
+            log.warn("BootEventHandler: 未找到设备 productKey={}, deviceName={}", productKey, deviceName);
+            return;
+        }
+
         // 更新设备状态
         washDeviceService.lambdaUpdate()
                 .set(WashDevice::getState, message.getPayload().getData().getDevice_state().getState())
-                .eq(WashDevice::getId, device.getId()).update();
+                .eq(WashDevice::getId, device.getId())
+                .update();
 
-        // 查询设备下的所有未完成的订单,如果有则将这些订单标记成异常结束
+        // 查询该设备下所有未支付订单,尝试对账结算
         var orderList = washOrderService.lambdaQuery()
                 .eq(WashOrder::getProductKey, productKey)
                 .eq(WashOrder::getDeviceName, deviceName)
                 .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
                 .list();
-        // todo 异常订单执行扣费操作
+
+        if (orderList.isEmpty()) {
+            return;
+        }
+
+        log.info("BootEventHandler: 设备 {}/{} 重启后发现 {} 个未支付订单", productKey, deviceName, orderList.size());
+
+        for (WashOrder order : orderList) {
+            try {
+                reconcileOrder(order, productKey, deviceName);
+            } catch (Exception e) {
+                log.error("BootEventHandler: 订单 {} 对账异常", order.getOrderId(), e);
+            }
+        }
+    }
+
+    private void reconcileOrder(WashOrder order, String productKey, String deviceName) {
+        try {
+            OrderInfo orderInfo = awoaraService.queryOrder(productKey, deviceName, order.getOrderId());
+
+            if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
+                log.info("BootEventHandler: 订单 {} 设备已关闭,执行结算", order.getOrderId());
+                orderSettlementService.settleOrder(order, orderInfo);
+                return;
+            }
+
+            if (orderInfo != null && (orderInfo.getClose_type() == null || orderInfo.getClose_type().isEmpty())) {
+                log.info("BootEventHandler: 订单 {} 设备仍在进行中,跳过", order.getOrderId());
+                return;
+            }
+
+            // 设备上查不到该订单(2G版本重启后无法查询历史订单)
+            log.warn("BootEventHandler: 订单 {} 在设备上未找到,标记待定时对账", order.getOrderId());
+            washOrderService.lambdaUpdate()
+                    .set(WashOrder::getStopReason, "设备重启,订单在设备上未找到,待定时对账")
+                    .eq(WashOrder::getId, order.getId())
+                    .update();
+
+        } catch (Exception e) {
+            log.warn("BootEventHandler: 订单 {} 查询设备失败: {}", order.getOrderId(), e.getMessage());
+            washOrderService.lambdaUpdate()
+                    .set(WashOrder::getStopReason, "设备重启,查询订单失败:" + e.getMessage())
+                    .eq(WashOrder::getId, order.getId())
+                    .update();
+        }
     }
 }

+ 2 - 1
car-wash-service/src/main/java/com/kym/service/awoara/event/handle/UserLoginEventHandler.java

@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
 
 /**
  * 用户登录事件(在机器上输入手机号+密码登录)
+ * 注:目前本系统业务不支持机器登录的方式,登录全部放在小程序端,故无需关注此情形
  *
  * @author skyline
  */
@@ -17,6 +18,6 @@ public class UserLoginEventHandler implements AwoaraEventHandler<UserLoginObject
     public void handle(MessageBody<UserLoginObject> message) {
         log.info(message.toString());
         log.info("UserLoginEventHandler");
-        // todo 如果机器支持登录,则完善业务逻辑(设备开机)
+        // 如果机器支持登录,则完善业务逻辑(设备开机)
     }
 }

+ 5 - 1
car-wash-service/src/main/java/com/kym/service/awoara/factory/AwoaraEventHandlerFactory.java

@@ -6,6 +6,7 @@ import com.kym.service.MonitorLogService;
 import com.kym.service.OrderSettlementService;
 import com.kym.service.WashDeviceService;
 import com.kym.service.WashOrderService;
+import com.kym.service.awoara.AwoaraService;
 import com.kym.service.awoara.event.handle.*;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.StringRedisTemplate;
@@ -26,12 +27,14 @@ public class AwoaraEventHandlerFactory {
     private static OrderSettlementService orderSettlementService;
     private static MonitorLogService monitorLogService;
     private static StringRedisTemplate stringRedisTemplate;
+    private static AwoaraService awoaraService;
 
 
     public AwoaraEventHandlerFactory(WashDeviceService washDeviceService, WashOrderService washOrderService,
                                      OrderSettlementService orderSettlementService,
                                      MonitorLogService monitorLogService,
                                      StringRedisTemplate stringRedisTemplate,
+                                     AwoaraService awoaraService,
     @Value("${kym.domain}") String domain) {
         DOMAIN = domain;
         AwoaraEventHandlerFactory.washDeviceService = washDeviceService;
@@ -39,13 +42,14 @@ public class AwoaraEventHandlerFactory {
         AwoaraEventHandlerFactory.orderSettlementService = orderSettlementService;
         AwoaraEventHandlerFactory.monitorLogService = monitorLogService;
         AwoaraEventHandlerFactory.stringRedisTemplate = stringRedisTemplate;
+        AwoaraEventHandlerFactory.awoaraService = awoaraService;
     }
 
     public static AwoaraEventHandler getEventHandler(String eventName) {
         try {
             Event event = Event.valueOf(eventName);
             return switch (event) {
-                case boot -> new BootEventHandler(washDeviceService, washOrderService);
+                case boot -> new BootEventHandler(washDeviceService, washOrderService, awoaraService, orderSettlementService);
                 case device_state -> new DeviceStateEventHandler(washDeviceService);
                 case order_create -> new OrderCreateEventHandler(washOrderService);
                 case order_update -> new OrderUpdateEventHandler(washOrderService);

+ 3 - 3
car-wash-service/src/main/java/com/kym/service/impl/StatServiceImpl.java

@@ -83,8 +83,8 @@ public class StatServiceImpl implements StatService {
         wrapper.gt(WashOrder::getStartTime, endTime);
         var list = washOrderService.list(wrapper);
         if (!list.isEmpty()) {
-            var totalSeconds = list.stream().mapToInt(WashOrder::getTotalSeconds).sum();
-            return totalSeconds / list.size();
+            var totalSeconds = list.stream().mapToLong(WashOrder::getTotalSeconds).sum();
+            return (int) (totalSeconds / list.size());
         }
         return null;
     }
@@ -131,7 +131,7 @@ public class StatServiceImpl implements StatService {
        var avgOrderPrice = todayOrders.isEmpty() ? 0 : (int)todayIncome/todayOrders.size();
        
         // 平均洗车时长(秒)
-       var avgOrderDuration = todayOrders.isEmpty() ? 0 : (int)todayOrders.stream().mapToInt(WashOrder::getTotalSeconds).sum() / todayOrders.size();
+       var avgOrderDuration = todayOrders.isEmpty() ? 0L : todayOrders.stream().mapToLong(WashOrder::getTotalSeconds).sum() / todayOrders.size();
 
         // 月度数据
         var monthOrders = washOrderService.lambdaQuery()