feat(inspection): 添加边缘端gRPC服务IP字段并优化报警去重逻辑
- 在AlertEnvelope中添加grpcIp字段用于前端展示和问题定位 - 将数据库表inspection_detection_alert的幂等键改为仅记录模式,使用event_id进行重复过滤 - 移除检测框明细表及相关处理逻辑,简化数据结构 - 更新麦克风和扬声器控制器的参数传递方式,统一使用RequestBody - 新增EdgeSpeakerPlayAudioVO类用于扬声器播放音频接口参数传递
This commit is contained in:
parent
ecda2b0ebc
commit
922d30632b
@ -6,12 +6,10 @@ import com.cmvr.edge.client.model.microphone.EdgeMicrophoneVolumeVO;
|
||||
import com.cmvr.edge.client.service.EdgeMicrophoneService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 麦克风管理
|
||||
@ -27,14 +25,17 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("获取麦克风状态")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:query')")
|
||||
@GetMapping("/status")
|
||||
public AjaxResult getStatus(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult getStatus(@ApiParam(value = "终端设备ID", required = true) @RequestParam String terminalId, @ApiParam (value = "设备ID", required = true) @RequestParam String deviceId) {
|
||||
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||
edgeCommonVO.setTerminalId(terminalId);
|
||||
edgeCommonVO.setDeviceId(deviceId);
|
||||
return AjaxResult.success(microphoneService.getStatus(edgeCommonVO));
|
||||
}
|
||||
|
||||
@ApiOperation("开始录音")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:record')")
|
||||
@PostMapping("/start")
|
||||
public AjaxResult startRecord(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult startRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
String filePath = microphoneService.startRecord(edgeCommonVO);
|
||||
return AjaxResult.success(filePath);
|
||||
}
|
||||
@ -42,7 +43,7 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("停止录音")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:stop')")
|
||||
@PostMapping("/stop")
|
||||
public AjaxResult stopRecord(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult stopRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
microphoneService.stopRecord(edgeCommonVO);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@ -50,7 +51,7 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("暂停录音")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:pause')")
|
||||
@PostMapping("/pause")
|
||||
public AjaxResult pauseRecord(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult pauseRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
microphoneService.pauseRecord(edgeCommonVO);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@ -58,7 +59,7 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("恢复录音")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:resume')")
|
||||
@PostMapping("/resume")
|
||||
public AjaxResult resumeRecord(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult resumeRecord(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
microphoneService.resumeRecord(edgeCommonVO);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@ -66,7 +67,7 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("设置音量")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
||||
@PostMapping("/volume")
|
||||
public AjaxResult setVolume(EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
||||
public AjaxResult setVolume(@RequestBody EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
||||
microphoneService.setVolume(edgeMicrophoneVolumeVO);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@ -74,7 +75,10 @@ public class EdgeMicrophoneController {
|
||||
@ApiOperation("获取音量")
|
||||
@PreAuthorize("@ss.hasPermi('system:microphone:volume')")
|
||||
@GetMapping("/volume")
|
||||
public AjaxResult getVolume(EdgeCommonVO edgeCommonVO) {
|
||||
public AjaxResult getVolume(@ApiParam(value = "终端设备ID", required = true) @RequestParam String terminalId, @ApiParam (value = "设备ID", required = true) @RequestParam String deviceId) {
|
||||
EdgeCommonVO edgeCommonVO = new EdgeCommonVO();
|
||||
edgeCommonVO.setTerminalId(terminalId);
|
||||
edgeCommonVO.setDeviceId(deviceId);
|
||||
return AjaxResult.success(microphoneService.getVolume(edgeCommonVO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package com.cmvr.web.controller.api;
|
||||
|
||||
import cmvr.api.SpeakerCommand;
|
||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||
import com.cmvr.edge.client.model.microphone.EdgeMicrophoneVolumeVO;
|
||||
import com.cmvr.edge.client.model.speaker.EdgeSpeakerPlayAudioVO;
|
||||
import com.cmvr.edge.client.service.EdgeSpeakerService;
|
||||
import com.cmvr.common.core.domain.AjaxResult;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -69,14 +72,8 @@ public class EdgeSpeakerController {
|
||||
@ApiOperation("播放音频")
|
||||
@PreAuthorize("@ss.hasPermi('system:speaker:play')")
|
||||
@PostMapping("/play")
|
||||
public AjaxResult playAudio(
|
||||
@ApiParam(value = "终端设备ID", required = true)
|
||||
@RequestParam String terminalId,
|
||||
@ApiParam(value = "设备ID", required = true)
|
||||
@RequestParam String deviceId,
|
||||
@ApiParam(value = "音频文件路径", required = true)
|
||||
@RequestParam String audioPath) {
|
||||
speakerService.playAudio(terminalId, deviceId, audioPath);
|
||||
public AjaxResult playAudio(@RequestBody EdgeSpeakerPlayAudioVO edgeSpeakerPlayAudioVO) {
|
||||
speakerService.playAudio(edgeSpeakerPlayAudioVO.getTerminalId(), edgeSpeakerPlayAudioVO.getDeviceId(), edgeSpeakerPlayAudioVO.getAudioPath());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@ -86,12 +83,8 @@ public class EdgeSpeakerController {
|
||||
@ApiOperation("停止播放")
|
||||
@PreAuthorize("@ss.hasPermi('system:speaker:stop')")
|
||||
@PostMapping("/stop")
|
||||
public AjaxResult stopPlayback(
|
||||
@ApiParam(value = "终端设备ID", required = true)
|
||||
@RequestParam String terminalId,
|
||||
@ApiParam(value = "设备ID", required = true)
|
||||
@RequestParam String deviceId) {
|
||||
speakerService.stopPlayback(terminalId, deviceId);
|
||||
public AjaxResult stopPlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
speakerService.stopPlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@ -101,12 +94,8 @@ public class EdgeSpeakerController {
|
||||
@ApiOperation("暂停播放")
|
||||
@PreAuthorize("@ss.hasPermi('system:speaker:pause')")
|
||||
@PostMapping("/pause")
|
||||
public AjaxResult pausePlayback(
|
||||
@ApiParam(value = "终端设备ID", required = true)
|
||||
@RequestParam String terminalId,
|
||||
@ApiParam(value = "设备ID", required = true)
|
||||
@RequestParam String deviceId) {
|
||||
speakerService.pausePlayback(terminalId, deviceId);
|
||||
public AjaxResult pausePlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
speakerService.pausePlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@ -116,12 +105,8 @@ public class EdgeSpeakerController {
|
||||
@ApiOperation("恢复播放")
|
||||
@PreAuthorize("@ss.hasPermi('system:speaker:resume')")
|
||||
@PostMapping("/resume")
|
||||
public AjaxResult resumePlayback(
|
||||
@ApiParam(value = "终端设备ID", required = true)
|
||||
@RequestParam String terminalId,
|
||||
@ApiParam(value = "设备ID", required = true)
|
||||
@RequestParam String deviceId) {
|
||||
speakerService.resumePlayback(terminalId, deviceId);
|
||||
public AjaxResult resumePlayback(@RequestBody EdgeCommonVO edgeCommonVO) {
|
||||
speakerService.resumePlayback(edgeCommonVO.getTerminalId(), edgeCommonVO.getDeviceId());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@ -131,14 +116,8 @@ public class EdgeSpeakerController {
|
||||
@ApiOperation("设置音量")
|
||||
@PreAuthorize("@ss.hasPermi('system:speaker:volume')")
|
||||
@PostMapping("/volume")
|
||||
public AjaxResult setVolume(
|
||||
@ApiParam(value = "终端设备ID", required = true)
|
||||
@RequestParam String terminalId,
|
||||
@ApiParam(value = "设备ID", required = true)
|
||||
@RequestParam String deviceId,
|
||||
@ApiParam(value = "音量大小(0-100)", required = true)
|
||||
@RequestParam int volume) {
|
||||
speakerService.setVolume(terminalId, deviceId, volume);
|
||||
public AjaxResult setVolume(@RequestBody EdgeMicrophoneVolumeVO edgeMicrophoneVolumeVO) {
|
||||
speakerService.setVolume(edgeMicrophoneVolumeVO.getTerminalId(), edgeMicrophoneVolumeVO.getDeviceId(), edgeMicrophoneVolumeVO.getVolume());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package com.cmvr.edge.client.model.speaker;
|
||||
|
||||
import com.cmvr.edge.client.model.EdgeCommonVO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* 扬声器播放音频请求参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("扬声器播放音频VO")
|
||||
public class EdgeSpeakerPlayAudioVO extends EdgeCommonVO {
|
||||
|
||||
@ApiModelProperty("音频文件路径")
|
||||
@NotEmpty(message = "音频文件路径不能为空")
|
||||
private String audioPath;
|
||||
}
|
||||
@ -26,6 +26,7 @@ public class InspectionDetectionAlert implements Serializable
|
||||
@TableField("schema_version")
|
||||
private String schema;
|
||||
private String sourceId;
|
||||
private String grpcIp;
|
||||
@TableField("source_sequence")
|
||||
private Long sequence;
|
||||
private Long capturedAtNs;
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
package com.cmvr.inspection.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* PPE 报警检测框明细实体。
|
||||
*/
|
||||
@Data
|
||||
@TableName("inspection_detection_detail")
|
||||
public class InspectionDetectionDetail implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.INPUT)
|
||||
private String id;
|
||||
|
||||
private String alertId;
|
||||
private String label;
|
||||
private Double confidence;
|
||||
private Double xMin;
|
||||
private Double yMin;
|
||||
private Double xMax;
|
||||
private Double yMax;
|
||||
private Long trackId;
|
||||
}
|
||||
@ -21,6 +21,10 @@ public class AlertEnvelope
|
||||
@JsonProperty("source_id")
|
||||
private String sourceId;
|
||||
|
||||
/** 边缘端 gRPC 服务 IP,用于前端展示和问题定位。 */
|
||||
@JsonProperty("grpc_ip")
|
||||
private String grpcIp;
|
||||
|
||||
/** 视频源内递增序号。 */
|
||||
@JsonProperty("sequence")
|
||||
private Long sequence;
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
package com.cmvr.inspection.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.cmvr.inspection.domain.InspectionDetectionDetail;
|
||||
|
||||
/**
|
||||
* PPE 报警检测框明细 Mapper。
|
||||
*/
|
||||
public interface InspectionDetectionDetailMapper extends BaseMapper<InspectionDetectionDetail>
|
||||
{
|
||||
}
|
||||
@ -11,7 +11,7 @@ public interface IInspectionDetectionAlertService
|
||||
* 接收并持久化一条 PPE 违规报警。
|
||||
*
|
||||
* @param envelope 报警信封
|
||||
* @param requestIdempotencyKey HTTP 请求头中的幂等键,允许为空
|
||||
* @param requestIdempotencyKey HTTP 请求头中的幂等键,仅记录,不用于重复过滤
|
||||
* @return true 表示本次新增,false 表示重复事件
|
||||
*/
|
||||
boolean receive(AlertEnvelope envelope, String requestIdempotencyKey);
|
||||
|
||||
@ -4,15 +4,11 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.cmvr.common.config.properties.MinioProperties;
|
||||
import com.cmvr.common.core.minio.MinioService;
|
||||
import com.cmvr.inspection.domain.InspectionDetectionAlert;
|
||||
import com.cmvr.inspection.domain.InspectionDetectionDetail;
|
||||
import com.cmvr.inspection.domain.dto.alert.AlertEnvelope;
|
||||
import com.cmvr.inspection.domain.dto.alert.AlertImage;
|
||||
import com.cmvr.inspection.domain.dto.alert.BoundingBox;
|
||||
import com.cmvr.inspection.domain.dto.alert.Detection;
|
||||
import com.cmvr.inspection.exception.DetectionAlertBadRequestException;
|
||||
import com.cmvr.inspection.exception.DetectionAlertTemporaryException;
|
||||
import com.cmvr.inspection.mapper.InspectionDetectionAlertMapper;
|
||||
import com.cmvr.inspection.mapper.InspectionDetectionDetailMapper;
|
||||
import com.cmvr.inspection.service.IInspectionDetectionAlertService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -27,7 +23,6 @@ import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -44,13 +39,11 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
private static final String SUPPORTED_SCHEMA = "DetectionAlert/v1";
|
||||
private static final String IMAGE_ENCODING_BASE64 = "base64";
|
||||
private static final String IMAGE_OBJECT_PREFIX = "inspection/detection-alerts";
|
||||
private static final int MAX_IDEMPOTENCY_KEY_LENGTH = 191;
|
||||
private static final int MAX_EVENT_ID_LENGTH = 128;
|
||||
private static final int MAX_IMAGE_BYTES = 10 * 1024 * 1024;
|
||||
private static final int MAX_BASE64_LENGTH = (MAX_IMAGE_BYTES * 4 / 3) + 8;
|
||||
|
||||
private final InspectionDetectionAlertMapper alertMapper;
|
||||
private final InspectionDetectionDetailMapper detailMapper;
|
||||
private final MinioService minioService;
|
||||
private final MinioProperties minioProperties;
|
||||
private final ObjectMapper objectMapper;
|
||||
@ -59,12 +52,12 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean receive(AlertEnvelope envelope, String requestIdempotencyKey)
|
||||
{
|
||||
String idempotencyKey = validateAndResolveIdempotencyKey(envelope, requestIdempotencyKey);
|
||||
String eventId = trimToNull(envelope.getPayload().getEventId());
|
||||
String eventId = validateAndResolveEventId(envelope);
|
||||
String idempotencyKey = trimToNull(requestIdempotencyKey);
|
||||
|
||||
if (exists(idempotencyKey, eventId))
|
||||
if (exists(eventId))
|
||||
{
|
||||
log.info("忽略重复PPE报警,idempotencyKey={},eventId={}", idempotencyKey, eventId);
|
||||
log.info("忽略重复PPE报警,eventId={}", eventId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -85,7 +78,6 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
}
|
||||
}
|
||||
|
||||
saveDetectionDetails(alert.getId(), envelope.getPayload().getDetections());
|
||||
log.info("PPE报警接收成功,alertId={},eventId={},sourceId={}",
|
||||
alert.getId(), eventId, envelope.getSourceId());
|
||||
return true;
|
||||
@ -102,9 +94,9 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验协议关键字段,并按请求头、event_id、trace_id 的顺序生成幂等键。
|
||||
* 校验协议关键字段,并返回用于重复过滤的 event_id。
|
||||
*/
|
||||
private String validateAndResolveIdempotencyKey(AlertEnvelope envelope, String requestIdempotencyKey)
|
||||
private String validateAndResolveEventId(AlertEnvelope envelope)
|
||||
{
|
||||
if (envelope == null)
|
||||
{
|
||||
@ -120,31 +112,17 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
}
|
||||
|
||||
String eventId = trimToNull(envelope.getPayload().getEventId());
|
||||
if (eventId != null && eventId.length() > MAX_EVENT_ID_LENGTH)
|
||||
if (eventId == null)
|
||||
{
|
||||
throw new DetectionAlertBadRequestException("payload.event_id不能为空");
|
||||
}
|
||||
if (eventId.length() > MAX_EVENT_ID_LENGTH)
|
||||
{
|
||||
throw new DetectionAlertBadRequestException("payload.event_id长度不能超过" + MAX_EVENT_ID_LENGTH);
|
||||
}
|
||||
|
||||
String idempotencyKey = trimToNull(requestIdempotencyKey);
|
||||
if (idempotencyKey == null)
|
||||
{
|
||||
idempotencyKey = eventId;
|
||||
}
|
||||
if (idempotencyKey == null)
|
||||
{
|
||||
idempotencyKey = trimToNull(envelope.getTraceId());
|
||||
}
|
||||
if (idempotencyKey == null)
|
||||
{
|
||||
throw new DetectionAlertBadRequestException("Idempotency-Key、payload.event_id和trace_id不能同时为空");
|
||||
}
|
||||
if (idempotencyKey.length() > MAX_IDEMPOTENCY_KEY_LENGTH)
|
||||
{
|
||||
throw new DetectionAlertBadRequestException("幂等键长度不能超过" + MAX_IDEMPOTENCY_KEY_LENGTH);
|
||||
}
|
||||
|
||||
validateImage(envelope.getPayload().getImage());
|
||||
return idempotencyKey;
|
||||
return eventId;
|
||||
}
|
||||
|
||||
private void validateImage(AlertImage image)
|
||||
@ -172,14 +150,10 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
}
|
||||
}
|
||||
|
||||
private boolean exists(String idempotencyKey, String eventId)
|
||||
private boolean exists(String eventId)
|
||||
{
|
||||
LambdaQueryWrapper<InspectionDetectionAlert> query = new LambdaQueryWrapper<>();
|
||||
query.eq(InspectionDetectionAlert::getIdempotencyKey, idempotencyKey);
|
||||
if (eventId != null)
|
||||
{
|
||||
query.or().eq(InspectionDetectionAlert::getEventId, eventId);
|
||||
}
|
||||
query.eq(InspectionDetectionAlert::getEventId, eventId);
|
||||
return alertMapper.selectCount(query) > 0;
|
||||
}
|
||||
|
||||
@ -192,6 +166,7 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
alert.setIdempotencyKey(idempotencyKey);
|
||||
alert.setSchema(envelope.getSchema());
|
||||
alert.setSourceId(envelope.getSourceId());
|
||||
alert.setGrpcIp(envelope.getGrpcIp());
|
||||
alert.setSequence(envelope.getSequence());
|
||||
alert.setCapturedAtNs(envelope.getCapturedAtNs());
|
||||
alert.setReceivedAtNs(envelope.getReceivedAtNs());
|
||||
@ -295,36 +270,6 @@ public class InspectionDetectionAlertServiceImpl implements IInspectionDetection
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDetectionDetails(String alertId, List<Detection> detections)
|
||||
{
|
||||
if (detections == null || detections.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (Detection detection : detections)
|
||||
{
|
||||
if (detection == null)
|
||||
{
|
||||
throw new DetectionAlertBadRequestException("payload.detections不能包含null元素");
|
||||
}
|
||||
InspectionDetectionDetail detail = new InspectionDetectionDetail();
|
||||
detail.setId(newId());
|
||||
detail.setAlertId(alertId);
|
||||
detail.setLabel(detection.getLabel());
|
||||
detail.setConfidence(detection.getConfidence());
|
||||
detail.setTrackId(detection.getTrackId());
|
||||
BoundingBox box = detection.getBox();
|
||||
if (box != null)
|
||||
{
|
||||
detail.setXMin(box.getXMin());
|
||||
detail.setYMin(box.getYMin());
|
||||
detail.setXMax(box.getXMax());
|
||||
detail.setYMax(box.getYMax());
|
||||
}
|
||||
detailMapper.insert(detail);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildMinioUrl(String objectName)
|
||||
{
|
||||
String baseUrl = StringUtils.removeEnd(minioProperties.getUrl(), "/");
|
||||
|
||||
@ -3,10 +3,11 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `inspection_detection_alert` (
|
||||
`id` varchar(32) NOT NULL COMMENT '主键ID',
|
||||
`event_id` varchar(128) DEFAULT NULL COMMENT '边缘端事件ID',
|
||||
`idempotency_key` varchar(191) NOT NULL COMMENT 'HTTP幂等键',
|
||||
`event_id` varchar(128) NOT NULL COMMENT '边缘端事件ID,用于重复过滤',
|
||||
`idempotency_key` varchar(191) DEFAULT NULL COMMENT 'HTTP幂等键,仅记录',
|
||||
`schema_version` varchar(64) NOT NULL COMMENT '消息结构版本',
|
||||
`source_id` varchar(128) DEFAULT NULL COMMENT '视频源标识',
|
||||
`grpc_ip` varchar(64) DEFAULT NULL COMMENT '边缘端gRPC服务IP',
|
||||
`source_sequence` bigint DEFAULT NULL COMMENT '视频源内消息序号',
|
||||
`captured_at_ns` bigint DEFAULT NULL COMMENT '采集时间Unix纳秒',
|
||||
`received_at_ns` bigint DEFAULT NULL COMMENT '边缘端接收时间Unix纳秒',
|
||||
@ -30,25 +31,44 @@ CREATE TABLE IF NOT EXISTS `inspection_detection_alert` (
|
||||
`created_at` datetime(3) NOT NULL COMMENT '平台接收时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_detection_alert_event_id` (`event_id`),
|
||||
UNIQUE KEY `uk_detection_alert_idempotency_key` (`idempotency_key`),
|
||||
KEY `idx_detection_alert_source_id` (`source_id`),
|
||||
KEY `idx_detection_alert_rule_id` (`rule_id`),
|
||||
KEY `idx_detection_alert_triggered_at` (`triggered_at_ns`),
|
||||
KEY `idx_detection_alert_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检PPE违规报警主表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `inspection_detection_detail` (
|
||||
`id` varchar(32) NOT NULL COMMENT '主键ID',
|
||||
`alert_id` varchar(32) NOT NULL COMMENT '报警主表ID',
|
||||
`label` varchar(128) DEFAULT NULL COMMENT '检测标签',
|
||||
`confidence` decimal(8,6) DEFAULT NULL COMMENT '检测置信度',
|
||||
`x_min` decimal(12,4) DEFAULT NULL COMMENT '目标框左上X坐标',
|
||||
`y_min` decimal(12,4) DEFAULT NULL COMMENT '目标框左上Y坐标',
|
||||
`x_max` decimal(12,4) DEFAULT NULL COMMENT '目标框右下X坐标',
|
||||
`y_max` decimal(12,4) DEFAULT NULL COMMENT '目标框右下Y坐标',
|
||||
`track_id` bigint DEFAULT NULL COMMENT '目标跟踪ID',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_detection_detail_alert_id` (`alert_id`),
|
||||
CONSTRAINT `fk_detection_detail_alert` FOREIGN KEY (`alert_id`)
|
||||
REFERENCES `inspection_detection_alert` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检PPE报警检测框明细表';
|
||||
SET @exist_grpc_ip := (
|
||||
SELECT COUNT(1)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'inspection_detection_alert'
|
||||
AND column_name = 'grpc_ip'
|
||||
);
|
||||
SET @add_grpc_ip_sql := IF(
|
||||
@exist_grpc_ip = 0,
|
||||
'ALTER TABLE `inspection_detection_alert` ADD COLUMN `grpc_ip` varchar(64) DEFAULT NULL COMMENT ''边缘端gRPC服务IP'' AFTER `source_id`',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE add_grpc_ip_stmt FROM @add_grpc_ip_sql;
|
||||
EXECUTE add_grpc_ip_stmt;
|
||||
DEALLOCATE PREPARE add_grpc_ip_stmt;
|
||||
|
||||
SET @exist_idempotency_unique := (
|
||||
SELECT COUNT(1)
|
||||
FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'inspection_detection_alert'
|
||||
AND index_name = 'uk_detection_alert_idempotency_key'
|
||||
);
|
||||
SET @drop_idempotency_unique_sql := IF(
|
||||
@exist_idempotency_unique > 0,
|
||||
'ALTER TABLE `inspection_detection_alert` DROP INDEX `uk_detection_alert_idempotency_key`',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE drop_idempotency_unique_stmt FROM @drop_idempotency_unique_sql;
|
||||
EXECUTE drop_idempotency_unique_stmt;
|
||||
DEALLOCATE PREPARE drop_idempotency_unique_stmt;
|
||||
|
||||
ALTER TABLE `inspection_detection_alert`
|
||||
MODIFY COLUMN `event_id` varchar(128) NOT NULL COMMENT '边缘端事件ID,用于重复过滤',
|
||||
MODIFY COLUMN `idempotency_key` varchar(191) DEFAULT NULL COMMENT 'HTTP幂等键,仅记录';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user