feat(aiot): 新增 Edge 告警上报和 resolve HTTP 端点

- POST /api/ai/alert/edge/report: 接收 Edge 告警,映射字段后入库
- POST /api/ai/alert/edge/resolve: 接收告警结束事件,更新持续时长
- AiAlertMapper 新增 updateDuration 方法

解决 Edge alarm_upload_worker 无法上报告警的问题。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 09:58:22 +08:00
parent d3c400de64
commit 8982e7e9b5
4 changed files with 61 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.aiot.controller;
import com.alibaba.fastjson2.JSON;
import com.genersoft.iot.vmp.aiot.bean.AiAlert;
import com.genersoft.iot.vmp.aiot.service.IAiAlertService;
import com.github.pagehelper.PageInfo;
@@ -58,4 +59,54 @@ public class AiAlertController {
@Parameter(description = "统计起始时间") @RequestParam(required = false, defaultValue = "2020-01-01 00:00:00") String startTime) {
return alertService.statistics(startTime);
}
// ==================== Edge 告警上报 ====================
@Operation(summary = "Edge 告警上报")
@PostMapping("/edge/report")
public void edgeReport(@RequestBody Map<String, Object> body) {
String alarmId = (String) body.get("alarm_id");
if (alarmId == null || alarmId.isEmpty()) {
log.warn("[AiAlert] Edge 上报缺少 alarm_id");
return;
}
AiAlert alert = new AiAlert();
alert.setAlertId(alarmId);
alert.setCameraId((String) body.get("device_id"));
alert.setRoiId((String) body.get("scene_id"));
alert.setAlertType((String) body.get("algorithm_code"));
alert.setImagePath((String) body.get("snapshot_url"));
alert.setReceivedAt((String) body.get("event_time"));
Object conf = body.get("confidence_score");
if (conf instanceof Number) {
alert.setConfidence(((Number) conf).doubleValue());
}
Object extData = body.get("ext_data");
if (extData != null) {
alert.setExtraData(JSON.toJSONString(extData));
}
alertService.save(alert);
log.info("[AiAlert] Edge 告警入库: alarmId={}, camera={}", alarmId, alert.getCameraId());
}
@Operation(summary = "Edge 告警结束上报")
@PostMapping("/edge/resolve")
public void edgeResolve(@RequestBody Map<String, Object> body) {
String alarmId = (String) body.get("alarm_id");
if (alarmId == null || alarmId.isEmpty()) {
log.warn("[AiAlert] Edge resolve 缺少 alarm_id");
return;
}
Object durationMs = body.get("duration_ms");
if (durationMs instanceof Number) {
double minutes = ((Number) durationMs).doubleValue() / 60_000.0;
alertService.updateDuration(alarmId, minutes);
log.info("[AiAlert] Edge 告警结束: alarmId={}, durationMin={}", alarmId, minutes);
}
}
}

View File

@@ -67,4 +67,7 @@ public interface AiAlertMapper {
@Select("SELECT camera_id, COUNT(*) as cnt FROM wvp_ai_alert " +
"WHERE received_at >= #{startTime} GROUP BY camera_id ORDER BY cnt DESC")
List<java.util.Map<String, Object>> statisticsByCamera(@Param("startTime") String startTime);
@Update("UPDATE wvp_ai_alert SET duration_minutes=#{durationMinutes} WHERE alert_id=#{alertId}")
int updateDuration(@Param("alertId") String alertId, @Param("durationMinutes") double durationMinutes);
}

View File

@@ -19,4 +19,6 @@ public interface IAiAlertService {
void deleteBatch(List<String> alertIds);
Map<String, Object> statistics(String startTime);
void updateDuration(String alertId, double durationMinutes);
}

View File

@@ -68,4 +68,9 @@ public class AiAlertServiceImpl implements IAiAlertService {
result.put("by_camera", alertMapper.statisticsByCamera(startTime));
return result;
}
@Override
public void updateDuration(String alertId, double durationMinutes) {
alertMapper.updateDuration(alertId, durationMinutes);
}
}