feat(ops,iot): 工单语音播报循环机制 + 统一按键逻辑
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled

核心改动:
- 新增循环播报机制:DISPATCHED 状态持续播报"工单来啦"直到按键确认
- 统一按键逻辑:confirmKeyId 和 queryKeyId 都路由到同一处理逻辑,
  根据工单状态智能判断行为(确认/查询/无工单提示)
- ARRIVED/COMPLETED 状态静默不播报,CANCELLED 保留取消播报
- 修复 P0:确认去重后按键不再静默,改为发查询事件给反馈
- 修复 P0:PAUSED 状态(P0打断)时停止被打断工单的循环播报
- 修复 P1:handleCompleted 补全 deviceId 兜底逻辑
- 修复 P1:stopLoop 只移除循环消息,保留非循环消息

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-02-26 17:13:03 +08:00
parent 6cb784a2d8
commit 5ee039b0bf
6 changed files with 281 additions and 75 deletions

View File

@@ -74,74 +74,62 @@ public class ButtonEventRuleProcessor {
log.debug("[ButtonEvent] 按键解析成功deviceId={}, buttonId={}", deviceId, buttonId);
// 4. 匹配按键类型并处理
if (buttonId.equals(buttonConfig.getConfirmKeyId())) {
// 确认键
handleConfirmButton(deviceId, buttonId);
} else if (buttonId.equals(buttonConfig.getQueryKeyId())) {
// 查询键
handleQueryButton(deviceId, buttonId);
// 4. 匹配按键类型并处理(确认键和查询键统一路由到同一逻辑)
if (buttonId.equals(buttonConfig.getConfirmKeyId())
|| buttonId.equals(buttonConfig.getQueryKeyId())) {
// 所有已知按键统一走绿色按键逻辑(根据工单状态智能判断行为)
handleGreenButton(deviceId, buttonId);
} else {
log.debug("[ButtonEvent] 未配置的按键deviceId={}, buttonId={}", deviceId, buttonId);
}
}
/**
* 处理确认按键
* 处理绿色按键(统一按键逻辑)
* <p>
* 保洁员按下确认键,确认接收工单
* 根据当前工单状态智能判断行为:
* - 无工单发布查询事件Ops 端播报"没有工单"
* - DISPATCHED发布确认事件触发确认状态转换 + 停止循环 + 播报地点)
* - CONFIRMED/ARRIVED发布查询事件播报地点
* - 其他状态:发布查询事件(兜底处理)
*/
private void handleConfirmButton(Long deviceId, Integer buttonId) {
log.info("[ButtonEvent] 确认键按下deviceId={}, buttonId={}", deviceId, buttonId);
// 1. 查询设备当前工单
BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
if (currentOrder == null) {
log.warn("[ButtonEvent] 设备无当前工单跳过确认deviceId={}", deviceId);
return;
}
Long orderId = currentOrder.getOrderId();
// 2. 防重复检查(短时间内同一工单的确认操作去重)
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;
}
// 3. 发布工单确认事件
publishConfirmEvent(deviceId, orderId, buttonId);
log.info("[ButtonEvent] 发布工单确认事件deviceId={}, orderId={}", deviceId, orderId);
}
/**
* 处理查询按键
* <p>
* 保洁员按下查询键,查询当前工单信息
*/
private void handleQueryButton(Long deviceId, Integer buttonId) {
log.info("[ButtonEvent] 查询键按下deviceId={}, buttonId={}", deviceId, buttonId);
private void handleGreenButton(Long deviceId, Integer buttonId) {
log.info("[ButtonEvent] 绿色按键按下deviceId={}, buttonId={}", deviceId, buttonId);
// 1. 查询设备当前工单
BadgeDeviceStatusRedisDAO.OrderInfo currentOrder = badgeDeviceStatusRedisDAO.getCurrentOrder(deviceId);
if (currentOrder == null) {
// 无工单 → 发布查询事件Ops 端播报"没有工单"
log.info("[ButtonEvent] 设备无当前工单deviceId={}", deviceId);
// 发布查询结果事件(无工单)
publishQueryEvent(deviceId, null, buttonId, "当前无工单");
return;
}
// 2. 发布查询事件
publishQueryEvent(deviceId, currentOrder.getOrderId(), buttonId, "查询当前工单");
Long orderId = currentOrder.getOrderId();
String orderStatus = currentOrder.getStatus();
log.info("[ButtonEvent] 发布工单查询事件deviceId={}, orderId={}", deviceId, currentOrder.getOrderId());
// 2. 根据工单状态智能分派
if ("DISPATCHED".equals(orderStatus)) {
// DISPATCHED → 发布确认事件(触发确认 + 停止循环 + 播报地点)
// 防重复检查
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 (!Boolean.TRUE.equals(firstTime)) {
// 重复确认不再静默,改为发查询事件给保洁员反馈(播报地点)
log.info("[ButtonEvent] 确认操作重复转为查询deviceId={}, orderId={}", deviceId, orderId);
publishQueryEvent(deviceId, orderId, buttonId, "重复确认,查询当前工单");
return;
}
publishConfirmEvent(deviceId, orderId, buttonId);
log.info("[ButtonEvent] DISPATCHED状态发布确认事件deviceId={}, orderId={}", deviceId, orderId);
} else {
// CONFIRMED / ARRIVED / 其他状态 → 发布查询事件(播报地点)
publishQueryEvent(deviceId, orderId, buttonId, "查询当前工单");
log.info("[ButtonEvent] {}状态发布查询事件deviceId={}, orderId={}", orderStatus, deviceId, orderId);
}
}
/**