diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java
index 58e6122..ee1bd2a 100644
--- a/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java
+++ b/viewsh-module-iot/viewsh-module-iot-server/src/main/java/com/viewsh/module/iot/service/rule/clean/processor/BeaconDetectionRuleProcessor.java
@@ -58,9 +58,9 @@ public class BeaconDetectionRuleProcessor {
*
* 在设备属性上报处理流程中调用此方法
*
- * @param deviceId 设备ID
- * @param identifier 属性标识符(bluetoothDevices)
- * @param propertyValue 属性值(蓝牙设备数组)
+ * @param deviceId 设备ID
+ * @param identifier 属性标识符(bluetoothDevices)
+ * @param propertyValue 属性值(蓝牙设备数组)
*/
public void processPropertyChange(Long deviceId, String identifier, Object propertyValue) {
// 1. 检查是否是蓝牙属性
@@ -71,8 +71,8 @@ public class BeaconDetectionRuleProcessor {
log.debug("[BeaconDetection] 收到蓝牙属性:deviceId={}", deviceId);
// 2. 获取工牌设备的配置(包含区域ID)
- CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper =
- configService.getConfigWrapperByDeviceId(deviceId);
+ CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper = configService
+ .getConfigWrapperByDeviceId(deviceId);
if (badgeConfigWrapper == null || badgeConfigWrapper.getAreaId() == null) {
log.debug("[BeaconDetection] 工牌设备无区域配置:deviceId={}", deviceId);
@@ -82,8 +82,8 @@ public class BeaconDetectionRuleProcessor {
Long areaId = badgeConfigWrapper.getAreaId();
// 3. 获取该区域的信标配置(从 BEACON 类型的设备获取)
- CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper beaconConfigWrapper =
- configService.getConfigByAreaIdAndRelationType(areaId, "BEACON");
+ CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper beaconConfigWrapper = configService
+ .getConfigByAreaIdAndRelationType(areaId, "BEACON");
if (beaconConfigWrapper == null || beaconConfigWrapper.getConfig() == null) {
log.debug("[BeaconDetection] 区域无信标配置:areaId={}", areaId);
@@ -110,19 +110,17 @@ public class BeaconDetectionRuleProcessor {
List window = windowRedisDAO.getWindow(deviceId, areaId);
// 6. 获取设备当前工单状态
- BadgeDeviceStatusRedisDAO.OrderInfo currentOrder =
- badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
+ BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
// 7. 确定当前状态
- RssiSlidingWindowDetector.AreaState currentState = determineState(currentOrder, areaId);
+ RssiSlidingWindowDetector.AreaState currentState = determineState(currentOrder, areaId, deviceId);
// 8. 执行检测
RssiSlidingWindowDetector.DetectionResult result = detector.detect(
window,
beaconConfig.getEnter(),
beaconConfig.getExit(),
- currentState
- );
+ currentState);
// 9. 处理检测结果
switch (result) {
@@ -142,8 +140,8 @@ public class BeaconDetectionRuleProcessor {
* 处理到达确认
*/
private void handleArriveConfirmed(Long deviceId, Long areaId, List window,
- BeaconPresenceConfig beaconConfig,
- CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper) {
+ BeaconPresenceConfig beaconConfig,
+ CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper badgeConfigWrapper) {
log.info("[BeaconDetection] 到达确认:deviceId={}, areaId={}, window={}",
deviceId, areaId, window);
@@ -177,10 +175,13 @@ public class BeaconDetectionRuleProcessor {
* 处理离开确认
*/
private void handleLeaveConfirmed(Long deviceId, Long areaId, List window,
- BeaconPresenceConfig beaconConfig) {
+ BeaconPresenceConfig beaconConfig) {
log.info("[BeaconDetection] 离开确认:deviceId={}, areaId={}, window={}",
deviceId, areaId, window);
+ // 注意:离岗警告阶段不清除arrivedTime,保持IN_AREA状态
+ // arrivedTime在工单完成时由SignalLossRuleProcessor.cleanupRedisData清除
+
// P0 插队校验:检查当前工单是否属于正在检查的区域
if (isSwitchingOrder(deviceId, areaId)) {
log.debug("[BeaconDetection][P0Interrupt] 检测到工单切换,跳过区域 {} 的离岗处理",
@@ -201,8 +202,8 @@ public class BeaconDetectionRuleProcessor {
// 2. 发送警告
publishTtsEvent(deviceId, "你已离开当前区域," +
- (exitConfig.getLossTimeoutMinutes() > 0 ?
- exitConfig.getLossTimeoutMinutes() + "分钟内工单将自动结算" : "工单将自动结算"));
+ (exitConfig.getLossTimeoutMinutes() > 0 ? exitConfig.getLossTimeoutMinutes() + "分钟内工单将自动结算"
+ : "工单将自动结算"));
// 3. 发布审计日志
Map data = new HashMap<>();
@@ -225,9 +226,17 @@ public class BeaconDetectionRuleProcessor {
*/
private void publishArriveEvent(Long deviceId, String deviceKey, Long areaId, Map triggerData) {
try {
+ // 获取当前工单信息,没有工单不发布事件
+ BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
+ if (currentOrder == null || currentOrder.getOrderId() == null) {
+ log.warn("[BeaconDetection] 设备无当前工单,跳过到岗事件: deviceId={}, areaId={}", deviceId, areaId);
+ return;
+ }
+
CleanOrderArriveEvent event = CleanOrderArriveEvent.builder()
.eventId(java.util.UUID.randomUUID().toString())
.orderType("CLEAN")
+ .orderId(currentOrder.getOrderId())
.deviceId(deviceId)
.deviceKey(deviceKey)
.areaId(areaId)
@@ -237,8 +246,8 @@ public class BeaconDetectionRuleProcessor {
rocketMQTemplate.syncSend(CleanOrderTopics.ORDER_ARRIVE, MessageBuilder.withPayload(event).build());
- log.info("[BeaconDetection] 发布到岗事件:eventId={}, deviceId={}, areaId={}",
- event.getEventId(), deviceId, areaId);
+ log.info("[BeaconDetection] 发布到岗事件:eventId={}, deviceId={}, areaId={}, orderId={}",
+ event.getEventId(), deviceId, areaId, currentOrder.getOrderId());
} catch (Exception e) {
log.error("[BeaconDetection] 发布到岗事件失败:deviceId={}, areaId={}", deviceId, areaId, e);
}
@@ -248,7 +257,7 @@ public class BeaconDetectionRuleProcessor {
* 发布审计事件
*/
private void publishAuditEvent(String auditType, Long deviceId, String deviceKey,
- Long areaId, String message, Map data) {
+ Long areaId, String message, Map data) {
try {
CleanOrderAuditEvent event = CleanOrderAuditEvent.builder()
.eventId(java.util.UUID.randomUUID().toString())
@@ -284,14 +293,24 @@ public class BeaconDetectionRuleProcessor {
* 确定当前状态
*/
private RssiSlidingWindowDetector.AreaState determineState(
- BadgeDeviceStatusRedisDAO.OrderInfo currentOrder, Long areaId) {
+ BadgeDeviceStatusRedisDAO.OrderInfo currentOrder, Long areaId, Long deviceId) {
- if (currentOrder == null) {
- return RssiSlidingWindowDetector.AreaState.OUT_AREA;
+ // 优先检查IoT本地到岗记录(避免依赖跨模块异步同步)
+ Long arrivedTime = arrivedTimeRedisDAO.getArrivedTime(deviceId, areaId);
+ if (arrivedTime != null) {
+ log.debug("[BeaconDetection] 本地状态:已到岗, deviceId={}, areaId={}, arrivedTime={}",
+ deviceId, areaId, arrivedTime);
+ return RssiSlidingWindowDetector.AreaState.IN_AREA;
}
- // 检查工单状态和区域是否匹配
- if ("ARRIVED".equals(currentOrder.getStatus()) && areaId.equals(currentOrder.getAreaId())) {
+ // 降级:检查Ops模块的工单状态(向后兼容)
+ if (currentOrder != null
+ && "ARRIVED".equals(currentOrder.getStatus())
+ && areaId.equals(currentOrder.getAreaId())) {
+ // 同步本地状态(修复历史数据)
+ arrivedTimeRedisDAO.recordArrivedTime(deviceId, areaId, System.currentTimeMillis());
+ log.info("[BeaconDetection] 从Ops状态同步本地到岗记录:deviceId={}, areaId={}",
+ deviceId, areaId);
return RssiSlidingWindowDetector.AreaState.IN_AREA;
}
@@ -308,8 +327,7 @@ public class BeaconDetectionRuleProcessor {
* @return true-工单切换场景,false-正常离岗场景
*/
private boolean isSwitchingOrder(Long deviceId, Long areaId) {
- BadgeDeviceStatusRedisDAO.OrderInfo currentOrder =
- badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
+ BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
return currentOrder != null && !currentOrder.getAreaId().equals(areaId);
}
}