feat(ops): 工牌实时状态增加物理位置、电量和工单信息
BadgeRealtimeStatusRespDTO 新增物理位置(IoT 轨迹检测 RPC)、 电量(IoT 设备属性 RPC)、当前工单信息三个维度。 RPC 调用改为串行执行避免占用 ForkJoinPool 公共线程。 设备状态写入 Redis 时同步写入区域名称。 Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package com.viewsh.module.ops.environment.service.badge;
|
||||
|
||||
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
|
||||
import com.viewsh.module.ops.dal.dataobject.area.OpsBusAreaDO;
|
||||
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
|
||||
import com.viewsh.module.ops.dal.mysql.area.OpsBusAreaMapper;
|
||||
import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
|
||||
import com.viewsh.module.ops.enums.BadgeDeviceStatusEnum;
|
||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
@@ -48,6 +50,9 @@ public class BadgeDeviceStatusServiceImpl implements BadgeDeviceStatusService, I
|
||||
@Resource
|
||||
private OpsOrderMapper opsOrderMapper;
|
||||
|
||||
@Resource
|
||||
private OpsBusAreaMapper opsBusAreaMapper;
|
||||
|
||||
@Resource
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@@ -400,6 +405,15 @@ public class BadgeDeviceStatusServiceImpl implements BadgeDeviceStatusService, I
|
||||
}
|
||||
if (areaId != null) {
|
||||
stringRedisTemplate.opsForHash().put(key, "currentAreaId", String.valueOf(areaId));
|
||||
// 同步写入区域名称
|
||||
try {
|
||||
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
||||
if (area != null && area.getAreaName() != null) {
|
||||
stringRedisTemplate.opsForHash().put(key, "currentAreaName", area.getAreaName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询区域名称失败: areaId={}", areaId, e);
|
||||
}
|
||||
}
|
||||
if (beaconMac != null) {
|
||||
stringRedisTemplate.opsForHash().put(key, "beaconMac", beaconMac);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package com.viewsh.module.ops.environment.service.badge;
|
||||
|
||||
import com.viewsh.framework.common.pojo.CommonResult;
|
||||
import com.viewsh.module.iot.api.device.IotDeviceControlApi;
|
||||
import com.viewsh.module.iot.api.device.IotDevicePropertyQueryApi;
|
||||
import com.viewsh.module.iot.api.device.dto.IotDeviceServiceInvokeReqDTO;
|
||||
import com.viewsh.module.iot.api.trajectory.DeviceLocationDTO;
|
||||
import com.viewsh.module.iot.api.trajectory.TrajectoryStateApi;
|
||||
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
|
||||
import com.viewsh.module.ops.api.clean.BadgeRealtimeStatusRespDTO;
|
||||
import com.viewsh.module.ops.api.clean.BadgeStatusRespDTO;
|
||||
import com.viewsh.module.ops.dal.dataobject.area.OpsBusAreaDO;
|
||||
import com.viewsh.module.ops.dal.mysql.area.OpsBusAreaMapper;
|
||||
import com.viewsh.module.ops.environment.service.badge.dto.BadgeNotifyReqDTO;
|
||||
import com.viewsh.module.ops.service.area.AreaDeviceService;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -39,8 +45,22 @@ public class CleanBadgeServiceImpl implements CleanBadgeService {
|
||||
@Resource
|
||||
private IotDeviceControlApi iotDeviceControlApi;
|
||||
|
||||
@Resource
|
||||
private TrajectoryStateApi trajectoryStateApi;
|
||||
|
||||
@Resource
|
||||
private IotDevicePropertyQueryApi iotDevicePropertyQueryApi;
|
||||
|
||||
@Resource
|
||||
private OpsBusAreaMapper opsBusAreaMapper;
|
||||
|
||||
private static final String NOTIFY_IDENTIFIER = "NOTIFY";
|
||||
|
||||
/**
|
||||
* IoT 设备属性标识符:电池电量
|
||||
*/
|
||||
private static final String BATTERY_LEVEL_IDENTIFIER = "batteryLevel";
|
||||
|
||||
@Override
|
||||
public List<BadgeStatusRespDTO> getBadgeStatusList(Long areaId, String status) {
|
||||
try {
|
||||
@@ -83,28 +103,52 @@ public class CleanBadgeServiceImpl implements CleanBadgeService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工牌实时状态详情
|
||||
* <p>
|
||||
* 聚合三个数据源:
|
||||
* 1. 工牌设备状态(Redis,本地)
|
||||
* 2. 工牌物理位置(IoT TrajectoryStateApi,RPC)
|
||||
* 3. 设备电量(IoT IotDevicePropertyQueryApi,RPC)
|
||||
*/
|
||||
@Override
|
||||
public BadgeRealtimeStatusRespDTO getBadgeRealtimeStatus(Long badgeId) {
|
||||
try {
|
||||
// 1. 获取工牌状态
|
||||
// 1. 获取工牌设备状态(Redis)
|
||||
BadgeDeviceStatusDTO status = badgeDeviceStatusService.getBadgeStatus(badgeId);
|
||||
if (status == null) {
|
||||
log.warn("[getBadgeRealtimeStatus] 工牌状态不存在: badgeId={}", badgeId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 构建响应
|
||||
return BadgeRealtimeStatusRespDTO.builder()
|
||||
// 2. 查询工牌物理位置 + 电量
|
||||
DeviceLocationDTO location = queryPhysicalLocation(badgeId);
|
||||
Integer batteryLevel = queryBatteryLevel(badgeId);
|
||||
|
||||
// 3. 组装响应
|
||||
BadgeRealtimeStatusRespDTO.BadgeRealtimeStatusRespDTOBuilder builder = BadgeRealtimeStatusRespDTO.builder()
|
||||
.deviceId(status.getDeviceId())
|
||||
.deviceKey(status.getDeviceCode())
|
||||
.status(status.getStatusCode())
|
||||
.batteryLevel(status.getBatteryLevel())
|
||||
.lastHeartbeatTime(formatTimestamp(status.getLastHeartbeatTime()))
|
||||
.rssi(null) // RSSI 需要从 IoT 模块获取,暂不实现
|
||||
.isInArea(status.getCurrentAreaId() != null)
|
||||
.areaId(status.getCurrentAreaId())
|
||||
.areaName(status.getCurrentAreaName())
|
||||
.build();
|
||||
.batteryLevel(batteryLevel)
|
||||
.onlineTime(formatTimestamp(status.getLastHeartbeatTime()));
|
||||
|
||||
// 物理位置
|
||||
if (location != null && Boolean.TRUE.equals(location.getInArea())) {
|
||||
builder.isInArea(true)
|
||||
.areaId(location.getAreaId())
|
||||
.areaName(queryAreaNameById(location.getAreaId()));
|
||||
} else {
|
||||
builder.isInArea(false);
|
||||
}
|
||||
|
||||
// 当前工单信息
|
||||
builder.currentOrderId(status.getCurrentOpsOrderId())
|
||||
.currentOrderStatus(status.getCurrentOrderStatus())
|
||||
.orderAreaId(status.getCurrentAreaId())
|
||||
.orderAreaName(status.getCurrentAreaName());
|
||||
|
||||
return builder.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[getBadgeRealtimeStatus] 查询工牌实时状态失败: badgeId={}", badgeId, e);
|
||||
@@ -112,6 +156,61 @@ public class CleanBadgeServiceImpl implements CleanBadgeService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询工牌物理位置(来自 IoT 轨迹检测 RPC)
|
||||
*
|
||||
* @return 位置信息,查询失败返回 null
|
||||
*/
|
||||
private DeviceLocationDTO queryPhysicalLocation(Long badgeId) {
|
||||
try {
|
||||
CommonResult<DeviceLocationDTO> result = trajectoryStateApi.getCurrentLocation(badgeId);
|
||||
if (result != null && result.isSuccess()) {
|
||||
return result.getData();
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.warn("[getBadgeRealtimeStatus] 查询工牌物理位置失败,降级为不在区域: badgeId={}", badgeId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询电量(来自 IoT 设备属性 RPC)
|
||||
*
|
||||
* @return 电量百分比(0-100),查询失败返回 null
|
||||
*/
|
||||
private Integer queryBatteryLevel(Long badgeId) {
|
||||
try {
|
||||
CommonResult<Map<String, Object>> result = iotDevicePropertyQueryApi.getLatestProperties(badgeId);
|
||||
if (result != null && result.isSuccess() && result.getData() != null) {
|
||||
Object batteryObj = result.getData().get(BATTERY_LEVEL_IDENTIFIER);
|
||||
if (batteryObj instanceof Number) {
|
||||
return ((Number) batteryObj).intValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.warn("[getBadgeRealtimeStatus] 查询工牌电量失败: badgeId={}", badgeId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据区域ID查询区域名称
|
||||
*/
|
||||
private String queryAreaNameById(Long areaId) {
|
||||
if (areaId == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
||||
return area != null ? area.queryAreaNameById() : null;
|
||||
} catch (Exception e) {
|
||||
log.warn("[getBadgeRealtimeStatus] 查询区域名称失败: areaId={}", areaId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBadgeNotify(BadgeNotifyReqDTO req) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user