feat(ops): add-iot-clean-order-integration阶段2-ButtonEventRuleProcessor补充

This commit is contained in:
lzh
2026-01-17 17:27:29 +08:00
parent 82966dc61b
commit 6933a22e1c

View File

@@ -0,0 +1,295 @@
package com.viewsh.module.iot.service.rule.clean.processor;
import com.viewsh.module.iot.core.integration.constants.CleanOrderTopics;
import com.viewsh.module.iot.dal.dataobject.integration.clean.ButtonEventConfig;
import com.viewsh.module.iot.dal.redis.clean.DeviceCurrentOrderRedisDAO;
import com.viewsh.module.iot.service.integration.clean.CleanOrderIntegrationConfigService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 按键事件规则处理器
* <p>
* 监听设备按键事件上报,处理保洁员工牌的按键交互
* <p>
* 支持的按键类型:
* - 确认键confirmKeyId保洁员确认接收工单
* - 查询键queryKeyId保洁员查询当前工单信息
*
* @author AI
*/
@Component
@Slf4j
public class ButtonEventRuleProcessor {
@Resource
private CleanOrderIntegrationConfigService configService;
@Resource
private DeviceCurrentOrderRedisDAO deviceCurrentOrderRedisDAO;
@Resource
private RocketMQTemplate rocketMQTemplate;
/**
* 处理按键事件属性上报
* <p>
* 在设备属性上报处理流程中调用此方法
*
* @param deviceId 设备ID
* @param identifier 属性标识符(如 button_event
* @param propertyValue 属性值
*/
public void processPropertyChange(Long deviceId, String identifier, Object propertyValue) {
// 1. 检查是否是按键事件属性
if (!"button_event".equals(identifier)) {
return;
}
log.debug("[ButtonEvent] 收到按键事件deviceId={}, value={}", deviceId, propertyValue);
// 2. 获取配置
CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper =
getConfigWrapper(deviceId);
if (configWrapper == null || configWrapper.getConfig() == null) {
log.debug("[ButtonEvent] 设备无配置deviceId={}", deviceId);
return;
}
ButtonEventConfig buttonConfig = configWrapper.getConfig().getButtonEvent();
if (buttonConfig == null || !buttonConfig.getEnabled()) {
log.debug("[ButtonEvent] 未启用按键事件处理deviceId={}", deviceId);
return;
}
// 3. 解析按键ID
Integer buttonId = parseButtonId(propertyValue);
if (buttonId == null) {
log.warn("[ButtonEvent] 按键ID解析失败deviceId={}, value={}", deviceId, propertyValue);
return;
}
log.debug("[ButtonEvent] 按键解析成功deviceId={}, buttonId={}", deviceId, buttonId);
// 4. 匹配按键类型并处理
if (buttonId.equals(buttonConfig.getConfirmKeyId())) {
// 确认键
handleConfirmButton(configWrapper, buttonId);
} else if (buttonId.equals(buttonConfig.getQueryKeyId())) {
// 查询键
handleQueryButton(configWrapper, buttonId);
} else {
log.debug("[ButtonEvent] 未配置的按键deviceId={}, buttonId={}", deviceId, buttonId);
}
}
/**
* 处理确认按键
* <p>
* 保洁员按下确认键,确认接收工单
*/
private void handleConfirmButton(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper,
Integer buttonId) {
Long deviceId = configWrapper.getDeviceId();
log.info("[ButtonEvent] 确认键按下deviceId={}, buttonId={}", deviceId, buttonId);
// 1. 查询设备当前工单
DeviceCurrentOrderRedisDAO.OrderCacheInfo currentOrderJson = deviceCurrentOrderRedisDAO.getCurrentOrder(deviceId);
if (currentOrderJson == null) {
log.warn("[ButtonEvent] 设备无当前工单跳过确认deviceId={}", deviceId);
return;
}
// 2. 解析工单ID简单解析生产环境可用 JSON 库)
Long orderId = extractOrderIdFromJson(currentOrderJson.getOrderId().toString());
if (orderId == null) {
log.warn("[ButtonEvent] 工单ID解析失败deviceId={}, json={}", deviceId, currentOrderJson);
return;
}
// 3. 防重复检查(短时间内同一工单的确认操作去重)
String dedupKey = String.format("iot:clean:button:dedup:confirm:%s:%s", deviceId, orderId);
Boolean firstTime = stringRedisTemplate.opsForValue()
.setIfAbsent(dedupKey, "1", 10, java.util.concurrent.TimeUnit.SECONDS);
if (!firstTime) {
log.info("[ButtonEvent] 确认操作重复跳过deviceId={}, orderId={}", deviceId, orderId);
return;
}
// 4. 发布工单确认事件
publishConfirmEvent(configWrapper, orderId, buttonId);
log.info("[ButtonEvent] 发布工单确认事件deviceId={}, orderId={}", deviceId, orderId);
}
/**
* 处理查询按键
* <p>
* 保洁员按下查询键,查询当前工单信息
*/
private void handleQueryButton(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper,
Integer buttonId) {
Long deviceId = configWrapper.getDeviceId();
log.info("[ButtonEvent] 查询键按下deviceId={}, buttonId={}", deviceId, buttonId);
// 1. 查询设备当前工单
DeviceCurrentOrderRedisDAO.OrderCacheInfo currentOrderJson = deviceCurrentOrderRedisDAO.getCurrentOrder(deviceId);
if (currentOrderJson == null) {
log.info("[ButtonEvent] 设备无当前工单deviceId={}", deviceId);
// 发布查询结果事件(无工单)
publishQueryEvent(configWrapper, null, buttonId, "当前无工单");
return;
}
// 2. 解析工单信息
Long orderId = extractOrderIdFromJson(currentOrderJson.getOrderId().toString());
if (orderId == null) {
log.warn("[ButtonEvent] 工单ID解析失败deviceId={}, json={}", deviceId, currentOrderJson);
return;
}
// 3. 发布查询事件
publishQueryEvent(configWrapper, orderId, buttonId, "查询当前工单");
log.info("[ButtonEvent] 发布工单查询事件deviceId={}, orderId={}", deviceId, orderId);
}
/**
* 发布工单确认事件
*/
private void publishConfirmEvent(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper,
Long orderId, Integer buttonId) {
try {
Map<String, Object> event = new HashMap<>();
event.put("eventId", UUID.randomUUID().toString());
event.put("orderType", "CLEAN");
event.put("orderId", orderId);
event.put("deviceId", configWrapper.getDeviceId());
event.put("deviceKey", configWrapper.getDeviceKey());
event.put("areaId", configWrapper.getAreaId());
event.put("triggerSource", "IOT_BUTTON_CONFIRM");
event.put("buttonId", buttonId);
rocketMQTemplate.syncSend(
CleanOrderTopics.ORDER_CONFIRM,
MessageBuilder.withPayload(event).build()
);
log.info("[ButtonEvent] 确认事件已发布eventId={}, orderId={}, deviceId={}",
event.get("eventId"), orderId, configWrapper.getDeviceId());
} catch (Exception e) {
log.error("[ButtonEvent] 发布确认事件失败deviceId={}, orderId={}",
configWrapper.getDeviceId(), orderId, e);
}
}
/**
* 发布工单查询事件
*/
private void publishQueryEvent(CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper configWrapper,
Long orderId, Integer buttonId, String message) {
try {
Map<String, Object> event = new HashMap<>();
event.put("eventId", UUID.randomUUID().toString());
event.put("orderType", "CLEAN");
event.put("orderId", orderId);
event.put("deviceId", configWrapper.getDeviceId());
event.put("deviceKey", configWrapper.getDeviceKey());
event.put("areaId", configWrapper.getAreaId());
event.put("triggerSource", "IOT_BUTTON_QUERY");
event.put("buttonId", buttonId);
event.put("message", message);
rocketMQTemplate.syncSend(
CleanOrderTopics.ORDER_AUDIT, // 查询事件使用审计主题
MessageBuilder.withPayload(event).build()
);
log.info("[ButtonEvent] 查询事件已发布eventId={}, orderId={}, deviceId={}, message={}",
event.get("eventId"), orderId, configWrapper.getDeviceId(), message);
} catch (Exception e) {
log.error("[ButtonEvent] 发布查询事件失败deviceId={}, orderId={}",
configWrapper.getDeviceId(), orderId, e);
}
}
/**
* 从 JSON 字符串中提取工单ID
* <p>
* 简单实现,生产环境建议使用 Jackson 或 Gson
*/
private Long extractOrderIdFromJson(String json) {
try {
// 简单解析:查找 "orderId":12345
int orderIdIndex = json.indexOf("\"orderId\"");
if (orderIdIndex == -1) {
return null;
}
int colonIndex = json.indexOf(":", orderIdIndex);
if (colonIndex == -1) {
return null;
}
int endIndex = json.indexOf(",", colonIndex);
if (endIndex == -1) {
endIndex = json.indexOf("}", colonIndex);
}
if (endIndex == -1) {
return null;
}
String idStr = json.substring(colonIndex + 1, endIndex).trim();
return Long.parseLong(idStr);
} catch (Exception e) {
log.error("[ButtonEvent] 解析工单ID失败json={}", json, e);
return null;
}
}
/**
* 获取配置包装器
*/
private CleanOrderIntegrationConfigService.AreaDeviceConfigWrapper getConfigWrapper(Long deviceId) {
return configService.getConfigWrapperByDeviceId(deviceId);
}
/**
* 解析按键ID
*/
private Integer parseButtonId(Object value) {
if (value == null) {
return null;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
return null;
}
}
return null;
}
@Resource
private StringRedisTemplate stringRedisTemplate;
}