feat(ops): 新增告警管理功能
添加告警请求VO、服务接口、服务实现及Controller,支持告警的基本管理操作。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2082
sql/mysql/aiot-platform.sql
Normal file
2082
sql/mysql/aiot-platform.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user