feat(ops): 新增轨迹统计接口 summary/hourly-trend/area-stay-stats

- summary: KPI 卡片(作业时长、覆盖区域数、事件数、平均停留)
- hourly-trend: 按小时聚合出入趋势
- area-stay-stats: 区域停留分布(含 fullAreaName,按时长降序)
- deviceId 可选,不传则汇总全部设备
- selectByDateAndDevice 加 LIMIT 5000 安全上限
- 删除无调用方的 selectTimeline 方法
- enrichWithAreaInfo 改用 buildPaths 批量构建路径

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
lzh
2026-04-05 15:26:14 +08:00
parent 368fa90156
commit 9ffaac5c91
5 changed files with 141 additions and 112 deletions

View File

@@ -68,16 +68,19 @@ public interface OpsDeviceTrajectoryMapper extends BaseMapperX<OpsDeviceTrajecto
}
/**
* 查询某设备某天的轨迹时间线(不分页,按进入时间升序
* 查询某天的轨迹记录deviceId 可选,为 null 则查全部设备
* <p>
* 安全上限 5000 条,防止全量加载过多数据到内存
*/
default List<OpsDeviceTrajectoryDO> selectTimeline(Long deviceId, LocalDate date) {
default List<OpsDeviceTrajectoryDO> selectByDateAndDevice(LocalDate date, Long deviceId) {
LocalDateTime start = date.atStartOfDay();
LocalDateTime end = date.plusDays(1).atStartOfDay();
return selectList(new LambdaQueryWrapperX<OpsDeviceTrajectoryDO>()
.eq(OpsDeviceTrajectoryDO::getDeviceId, deviceId)
.eqIfPresent(OpsDeviceTrajectoryDO::getDeviceId, deviceId)
.ge(OpsDeviceTrajectoryDO::getEnterTime, start)
.lt(OpsDeviceTrajectoryDO::getEnterTime, end)
.orderByAsc(OpsDeviceTrajectoryDO::getEnterTime));
.orderByAsc(OpsDeviceTrajectoryDO::getEnterTime)
.last("LIMIT 5000"));
}
}

View File

@@ -20,22 +20,16 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
public class TrajectorySummaryDTO {
@Schema(description = "轨迹记录数(含未关闭)", example = "42")
private Long totalRecords;
@Schema(description = "作业时长(秒)", example = "7200")
private Long workDurationSeconds;
@Schema(description = "已完成记录数(有离开时间)", example = "38")
private Long completedRecords;
@Schema(description = "覆盖区域数", example = "8")
@Schema(description = "覆盖区域数", example = "5")
private Long coveredAreaCount;
@Schema(description = "停留时长(秒)", example = "28800")
private Long totalDurationSeconds;
@Schema(description = "出入事件数", example = "42")
private Long totalEvents;
@Schema(description = "平均停留时长(秒)", example = "685")
private Long avgDurationSeconds;
@Schema(description = "最长单次停留(秒)", example = "3600")
private Long maxDurationSeconds;
@Schema(description = "平均停留时长(秒)", example = "171")
private Long avgStaySeconds;
}