feat(ops): 统一语音播报模板管理

- 新建 CleanNotificationConstants 类,集中管理所有播报模板
- VoiceTemplate: 定义各种场景的播报模板常量
- VoiceBuilder: 提供构建器方法,支持参数化和标题截断
- NotifyParamsBuilder: 站内信参数构建辅助方法
- 更新 CleanOrderAuditEventHandler 查询播报为显示当前工单而非位置

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-01-25 18:21:04 +08:00
parent 577fd25f8e
commit 8782a530fe
4 changed files with 607 additions and 66 deletions

View File

@@ -0,0 +1,152 @@
package com.viewsh.module.iot.dal.redis.clean;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 工牌设备状态 Redis DAO只读
* <p>
* 从 Redis 读取由 Ops 模块写入的工牌设备状态信息
* Key: ops:badge:status:{deviceId}
* 数据结构: Hash
* <p>
* IoT 模块只读取此数据<E68DAE><EFBC8C>操作由 Ops 模块的 BadgeDeviceStatusService 处理
*
* @author AI
*/
@Repository
public class BadgeDeviceStatusRedisDAO {
/**
* 工牌状态 Key 模式
* <p>
* 格式ops:badge:status:{deviceId}
*/
private static final String BADGE_STATUS_KEY_PATTERN = "ops:badge:status:%s";
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 获取设备当前工单信息
*
* @param deviceId 设备ID
* @return 工单信息,如果不存在返回 null
*/
public OrderInfo getCurrentOrder(Long deviceId) {
String key = formatKey(deviceId);
Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(key);
if (map == null || map.isEmpty()) {
return null;
}
// 提取工单相关字段
OrderInfo orderInfo = new OrderInfo();
orderInfo.setOrderId(getLong(map.get("currentOpsOrderId")));
orderInfo.setStatus((String) map.get("currentOrderStatus"));
orderInfo.setAreaId(getLong(map.get("currentAreaId")));
orderInfo.setBeaconMac((String) map.get("beaconMac"));
// 如果没有工单ID返回 null
if (orderInfo.getOrderId() == null) {
return null;
}
return orderInfo;
}
/**
* 获取设备完整状态信息(原始 Map
*
* @param deviceId 设备ID
* @return 状态信息 Map如果不存在返回空 Map
*/
public Map<String, String> getBadgeStatus(Long deviceId) {
String key = formatKey(deviceId);
Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(key);
if (map == null || map.isEmpty()) {
return new HashMap<>();
}
Map<String, String> result = new HashMap<>();
for (Map.Entry<Object, Object> entry : map.entrySet()) {
result.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
return result;
}
/**
* 检查设备是否有当前工单
*
* @param deviceId 设备ID
* @return 是否有工单
*/
public boolean hasCurrentOrder(Long deviceId) {
String key = formatKey(deviceId);
return Boolean.TRUE.equals(stringRedisTemplate.opsForHash().hasKey(key, "currentOpsOrderId"));
}
/**
* 获取 Hash 中的 Long 字段值
*/
private Long getLong(Object value) {
if (value == null) {
return null;
}
if (value instanceof Long) {
return (Long) value;
}
try {
return Long.parseLong(value.toString());
} catch (Exception e) {
return null;
}
}
/**
* 格式化 Redis Key
*/
private static String formatKey(Long deviceId) {
return String.format(BADGE_STATUS_KEY_PATTERN, deviceId);
}
/**
* 工单信息(精简 DTO
* <p>
* 只包含 IoT 模块需要的工单字段
*/
@Getter
@Setter
public static class OrderInfo {
/**
* 工单ID
*/
private Long orderId;
/**
* 工单状态
* <p>
* DISPATCHED/ARRIVED/PAUSED/COMPLETED
*/
private String status;
/**
* 区域ID
*/
private Long areaId;
/**
* 信标 MAC 地址
*/
private String beaconMac;
}
}