feat(ops): 新增告警管理功能
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled

添加告警请求VO、服务接口、服务实现及Controller,支持告警的基本管理操作。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-02-13 09:30:57 +08:00
parent b851484e4e
commit c9195f78e9
5 changed files with 2269 additions and 0 deletions

2082
sql/mysql/aiot-platform.sql Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
package com.viewsh.module.ops.dal.dataobject.vo.alarm;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 告警推送 Request VO
*/
@Schema(description = "告警推送 Request VO")
@Data
public class OpsAlarmReqVO {
@Schema(description = "告警ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "ALM20260211001")
@NotBlank(message = "告警ID不能为空")
private String alarmId;
@Schema(description = "告警类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "FIRE")
@NotBlank(message = "告警类型不能为空")
private String alarmType;
@Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "CAM_001")
@NotBlank(message = "设备ID不能为空")
private String deviceId;
@Schema(description = "事件时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "事件时间不能为空")
private LocalDateTime eventTime;
@Schema(description = "告警级别(1-4)", example = "2")
private Integer alarmLevel;
@Schema(description = "截图URL", example = "https://oss.example.com/snapshot/xxx.jpg")
private String snapshotUrl;
@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "租户编号不能为空")
private Long tenantId;
@Schema(description = "站内信通知用户ID列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
@NotEmpty(message = "通知用户列表不能为空")
private List<Long> notifyUserIds;
@Schema(description = "扩展数据", example = "{\"algorithmCode\":\"ALGO_FIRE\",\"confidenceScore\":0.95}")
private Map<String, Object> extData;
}

View File

@@ -0,0 +1,17 @@
package com.viewsh.module.ops.service.alarm;
import com.viewsh.module.ops.dal.dataobject.vo.alarm.OpsAlarmReqVO;
/**
* 告警服务接口
*/
public interface OpsAlarmService {
/**
* 接收告警并发送站内信通知
*
* @param reqVO 告警信息
*/
void receiveAlarm(OpsAlarmReqVO reqVO);
}

View File

@@ -0,0 +1,74 @@
package com.viewsh.module.ops.service.alarm;
import com.viewsh.framework.tenant.core.util.TenantUtils;
import com.viewsh.module.ops.dal.dataobject.vo.alarm.OpsAlarmReqVO;
import com.viewsh.module.system.api.notify.NotifyMessageSendApi;
import com.viewsh.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.HashMap;
import java.util.Map;
/**
* 告警服务实现
*/
@Slf4j
@Service
@Validated
public class OpsAlarmServiceImpl implements OpsAlarmService {
/**
* 告警站内信模板编号(需在 notify_template 表中配置)
* 模板参数: {alarmId}, {alarmType}, {deviceId}, {eventTime}
*/
private static final String ALARM_NOTIFY_TEMPLATE = "OPS_ALARM_NOTIFY";
@Resource
private NotifyMessageSendApi notifyMessageSendApi;
@Override
public void receiveAlarm(OpsAlarmReqVO reqVO) {
Map<String, Object> templateParams = buildTemplateParams(reqVO);
// 在指定租户上下文中发送站内信
TenantUtils.execute(reqVO.getTenantId(), () -> {
for (Long userId : reqVO.getNotifyUserIds()) {
sendNotifyMessage(userId, templateParams);
}
});
log.info("[告警通知已发送] alarmId={}, alarmType={}, deviceId={}, tenantId={}, 通知人数={}",
reqVO.getAlarmId(), reqVO.getAlarmType(), reqVO.getDeviceId(),
reqVO.getTenantId(), reqVO.getNotifyUserIds().size());
}
private Map<String, Object> buildTemplateParams(OpsAlarmReqVO reqVO) {
Map<String, Object> params = new HashMap<>();
params.put("alarmId", reqVO.getAlarmId());
params.put("alarmType", reqVO.getAlarmType());
params.put("deviceId", reqVO.getDeviceId());
params.put("eventTime", reqVO.getEventTime().toString());
if (reqVO.getAlarmLevel() != null) {
params.put("alarmLevel", reqVO.getAlarmLevel());
}
if (reqVO.getSnapshotUrl() != null) {
params.put("snapshotUrl", reqVO.getSnapshotUrl());
}
return params;
}
private void sendNotifyMessage(Long userId, Map<String, Object> templateParams) {
try {
NotifySendSingleToUserReqDTO reqDTO = new NotifySendSingleToUserReqDTO();
reqDTO.setUserId(userId);
reqDTO.setTemplateCode(ALARM_NOTIFY_TEMPLATE);
reqDTO.setTemplateParams(templateParams);
notifyMessageSendApi.sendSingleMessageToAdmin(reqDTO);
} catch (Exception e) {
log.error("[告警站内信发送失败] userId={}", userId, e);
}
}
}

View File

@@ -0,0 +1,43 @@
package com.viewsh.module.ops.controller.admin.alarm;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.framework.tenant.core.aop.TenantIgnore;
import com.viewsh.module.ops.dal.dataobject.vo.alarm.OpsAlarmReqVO;
import com.viewsh.module.ops.service.alarm.OpsAlarmService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static com.viewsh.framework.common.pojo.CommonResult.success;
/**
* 告警接收接口(对外开放)
*/
@Tag(name = "Open API - 告警接收")
@Slf4j
@RestController
@RequestMapping("/ops/alarm")
@Validated
public class OpsAlarmController {
@Resource
private OpsAlarmService opsAlarmService;
@PostMapping("/receive")
@Operation(summary = "接收告警并发送站内信通知")
@PermitAll
@TenantIgnore
public CommonResult<Boolean> receiveAlarm(@Valid @RequestBody OpsAlarmReqVO reqVO) {
opsAlarmService.receiveAlarm(reqVO);
return success(true);
}
}