From cb075c907d7ab14b1e4dab806b78880f9ea1ea80 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Mon, 10 Nov 2025 18:22:00 +0800 Subject: [PATCH] DeleteDeviceThresholdAlarm DeleteAreaThresholdAlarm --- design/exceeding-threshold-alarm/index.md | 3 +- internal/app/dto/alarm_dto.go | 5 + internal/app/dto/monitor_converter.go | 2 +- internal/app/dto/plan_converter.go | 6 +- .../app/service/threshold_alarm_service.go | 113 ++++++++++++++++++ internal/core/component_initializers.go | 4 + internal/core/data_initializer.go | 6 +- 7 files changed, 131 insertions(+), 8 deletions(-) diff --git a/design/exceeding-threshold-alarm/index.md b/design/exceeding-threshold-alarm/index.md index 4959eac..aa57023 100644 --- a/design/exceeding-threshold-alarm/index.md +++ b/design/exceeding-threshold-alarm/index.md @@ -139,4 +139,5 @@ 7. 实现忽略告警和取消忽略告警接口及功能 8. 实现列表查询活跃告警和历史告警 9. 系统初始化时健康计划调整(包括增加延时任务) -10. 实现区域阈值告警任务 \ No newline at end of file +10. 实现区域阈值告警任务 +11. 实现区域阈值告警和设备阈值告警的增删改查 \ No newline at end of file diff --git a/internal/app/dto/alarm_dto.go b/internal/app/dto/alarm_dto.go index 2f097c6..bf55fb9 100644 --- a/internal/app/dto/alarm_dto.go +++ b/internal/app/dto/alarm_dto.go @@ -114,6 +114,11 @@ type UpdateAreaThresholdAlarmDTO struct { Level models.SeverityLevel `json:"level,omitempty"` // 新的告警等级,可选 } +// DeleteDeviceThresholdAlarmDTO 删除设备阈值告警的请求DTO +type DeleteDeviceThresholdAlarmDTO struct { + SensorType models.SensorType `json:"sensor_type" binding:"required"` // 传感器类型 +} + // AreaThresholdAlarmDTO 用于表示一个区域阈值告警任务的详细信息 type AreaThresholdAlarmDTO struct { ID int `json:"id"` diff --git a/internal/app/dto/monitor_converter.go b/internal/app/dto/monitor_converter.go index c45d597..f7192f0 100644 --- a/internal/app/dto/monitor_converter.go +++ b/internal/app/dto/monitor_converter.go @@ -56,7 +56,7 @@ func NewListDeviceCommandLogResponse(data []models.DeviceCommandLog, total int64 func NewListPlanExecutionLogResponse(planLogs []models.PlanExecutionLog, plans []models.Plan, total int64, page, pageSize int) *ListPlanExecutionLogResponse { planId2Name := make(map[uint]string) for _, plan := range plans { - planId2Name[plan.ID] = plan.Name + planId2Name[plan.ID] = string(plan.Name) } dtos := make([]PlanExecutionLogDTO, len(planLogs)) diff --git a/internal/app/dto/plan_converter.go b/internal/app/dto/plan_converter.go index adc018c..e7313cc 100644 --- a/internal/app/dto/plan_converter.go +++ b/internal/app/dto/plan_converter.go @@ -15,7 +15,7 @@ func NewPlanToResponse(plan *models.Plan) (*PlanResponse, error) { response := &PlanResponse{ ID: plan.ID, - Name: plan.Name, + Name: string(plan.Name), Description: plan.Description, PlanType: plan.PlanType, ExecutionType: plan.ExecutionType, @@ -60,7 +60,7 @@ func NewPlanFromCreateRequest(req *CreatePlanRequest) (*models.Plan, error) { } plan := &models.Plan{ - Name: req.Name, + Name: models.PlanName(req.Name), Description: req.Description, ExecutionType: req.ExecutionType, ExecuteNum: req.ExecuteNum, @@ -103,7 +103,7 @@ func NewPlanFromUpdateRequest(req *UpdatePlanRequest) (*models.Plan, error) { } plan := &models.Plan{ - Name: req.Name, + Name: models.PlanName(req.Name), Description: req.Description, ExecutionType: req.ExecutionType, ExecuteNum: req.ExecuteNum, diff --git a/internal/app/service/threshold_alarm_service.go b/internal/app/service/threshold_alarm_service.go index 82d65ed..e954919 100644 --- a/internal/app/service/threshold_alarm_service.go +++ b/internal/app/service/threshold_alarm_service.go @@ -32,12 +32,17 @@ type ThresholdAlarmService interface { UpdateDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.UpdateDeviceThresholdAlarmDTO) error // GetDeviceThresholdAlarm 根据ID获取一个设备阈值告警任务。 GetDeviceThresholdAlarm(ctx context.Context, taskID int) (*dto.DeviceThresholdAlarmDTO, error) + // DeleteDeviceThresholdAlarm 删除一个设备阈值告警。 + DeleteDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.DeleteDeviceThresholdAlarmDTO) error + // CreateAreaThresholdAlarm 创建一个区域阈值告警。 CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error // UpdateAreaThresholdAlarm 更新一个区域阈值告警。 UpdateAreaThresholdAlarm(ctx context.Context, taskID int, req *dto.UpdateAreaThresholdAlarmDTO) error // GetAreaThresholdAlarm 根据ID获取一个区域阈值告警任务。 GetAreaThresholdAlarm(ctx context.Context, taskID int) (*dto.AreaThresholdAlarmDTO, error) + // DeleteAreaThresholdAlarm 实现了删除一个区域阈值告警的逻辑。 + DeleteAreaThresholdAlarm(ctx context.Context, taskID int) error } // thresholdAlarmService 是 ThresholdAlarmService 接口的具体实现。 @@ -48,6 +53,7 @@ type thresholdAlarmService struct { alarmRepo repository.AlarmRepository planRepo repository.PlanRepository + areaRepo repository.AreaControllerRepository deviceRepo repository.DeviceRepository } @@ -57,6 +63,7 @@ func NewThresholdAlarmService(ctx context.Context, planService plan.Service, alarmRepo repository.AlarmRepository, planRepo repository.PlanRepository, + areaRepo repository.AreaControllerRepository, deviceRepo repository.DeviceRepository, ) ThresholdAlarmService { return &thresholdAlarmService{ @@ -65,6 +72,7 @@ func NewThresholdAlarmService(ctx context.Context, planService: planService, alarmRepo: alarmRepo, planRepo: planRepo, + areaRepo: areaRepo, deviceRepo: deviceRepo, } } @@ -291,6 +299,77 @@ func (s *thresholdAlarmService) GetDeviceThresholdAlarm(ctx context.Context, tas return resp, nil } +// DeleteDeviceThresholdAlarm 实现了删除一个设备阈值告警的逻辑。 +func (s *thresholdAlarmService) DeleteDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.DeleteDeviceThresholdAlarmDTO) error { + serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeleteDeviceThresholdAlarm") + + // 获取待删除任务并校验 + deleteTask, err := s.planRepo.FindTaskByID(serviceCtx, taskID) + if err != nil { + return fmt.Errorf("获取任务失败: %w", err) + } + if deleteTask.Type != models.TaskTypeDeviceThresholdCheck { + return fmt.Errorf("任务 %d 不是一个设备阈值检查任务", taskID) + } + var deviceParams task.DeviceThresholdCheckParams + if err := deleteTask.ParseParameters(&deviceParams); err != nil { + return fmt.Errorf("任务 %d: 解析参数失败: %w", taskID, err) + } + + // 获得任务对应设备对应区域主控 + device, err := s.deviceRepo.FindByID(serviceCtx, deviceParams.DeviceID) + if err != nil { + return fmt.Errorf("获取设备 %d 失败: %w", deviceParams.DeviceID, err) + } + area, err := s.areaRepo.FindByID(serviceCtx, device.AreaControllerID) + if err != nil { + return fmt.Errorf("获取区域 %d 失败: %w", device.AreaControllerID, err) + } + + // 获取健康检查计划任务列表 + plan, err := s.planRepo.GetSystemPlanByName(serviceCtx, models.PlanNamePeriodicSystemHealthCheck) + if err != nil { + return fmt.Errorf("获取系统健康检查计划失败: %w", err) + } + if plan == nil { + logger.Panicf("系统计划 %v 不存在", models.PlanNamePeriodicSystemHealthCheck) + } + + taskIndexToDelete := -1 + for i, t := range plan.Tasks { + if t.ID == taskID { + taskIndexToDelete = i + } + if t.Type == models.TaskTypeAreaCollectorThresholdCheck { + var areaParams task.AreaThresholdCheckParams + if err := t.ParseParameters(&areaParams); err != nil { + return fmt.Errorf("任务 %d: 解析参数失败: %w", t.ID, err) + } + if areaParams.AreaControllerID == area.ID && areaParams.SensorType == deviceParams.SensorType { + for ia, e := range areaParams.ExcludeDeviceIDs { + if e == deviceParams.DeviceID { + areaParams.ExcludeDeviceIDs = append(areaParams.ExcludeDeviceIDs[:ia], areaParams.ExcludeDeviceIDs[ia+1:]...) + continue + } + } + err = plan.Tasks[i].SaveParameters(areaParams) + if err != nil { + return fmt.Errorf("任务 %d: 保存参数失败: %w", t.ID, err) + } + } + } + } + + if taskIndexToDelete == -1 { + return fmt.Errorf("任务 %d 在系统计划中未找到", taskID) + } + plan.Tasks = append(plan.Tasks[:taskIndexToDelete], plan.Tasks[taskIndexToDelete+1:]...) + + plan.ReorderSteps() + _, err = s.planService.UpdatePlan(serviceCtx, plan, models.PlanTypeSystem) + return err +} + // CreateAreaThresholdAlarm 实现了创建一个区域阈值告警的逻辑。 func (s *thresholdAlarmService) CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error { serviceCtx, logger := logs.Trace(ctx, s.ctx, "CreateAreaThresholdAlarm") @@ -442,3 +521,37 @@ func (s *thresholdAlarmService) GetAreaThresholdAlarm(ctx context.Context, taskI } return resp, nil } + +// DeleteAreaThresholdAlarm 实现了删除一个区域阈值告警的逻辑。 +func (s *thresholdAlarmService) DeleteAreaThresholdAlarm(ctx context.Context, taskID int) error { + serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeleteAreaThresholdAlarm") + + // 获取健康检查计划任务列表 + plan, err := s.planRepo.GetSystemPlanByName(serviceCtx, models.PlanNamePeriodicSystemHealthCheck) + if err != nil { + return fmt.Errorf("获取系统健康检查计划失败: %w", err) + } + if plan == nil { + logger.Panicf("系统计划 %v 不存在", models.PlanNamePeriodicSystemHealthCheck) + } + + // 找到这个任务并删掉 + deleteTaskNum := -1 + for i, t := range plan.Tasks { + if t.Type != models.TaskTypeAreaCollectorThresholdCheck { + continue + } + if t.ID != taskID { + continue + } + deleteTaskNum = i + } + + if deleteTaskNum == -1 { + return fmt.Errorf("任务 %d: 不存在或类型不匹配", taskID) + } + plan.Tasks = append(plan.Tasks[:deleteTaskNum], plan.Tasks[deleteTaskNum+1:]...) + plan.ReorderSteps() + _, err = s.planService.UpdatePlan(serviceCtx, plan, models.PlanTypeSystem) + return err +} diff --git a/internal/core/component_initializers.go b/internal/core/component_initializers.go index af77dec..f2b0560 100644 --- a/internal/core/component_initializers.go +++ b/internal/core/component_initializers.go @@ -269,7 +269,11 @@ func initAppServices(ctx context.Context, infra *Infrastructure, domainServices thresholdAlarmService := service.NewThresholdAlarmService( logs.AddCompName(baseCtx, "ThresholdAlarmService"), domainServices.alarmService, + domainServices.planService, infra.repos.alarmRepo, + infra.repos.planRepo, + infra.repos.areaControllerRepo, + infra.repos.deviceRepo, ) return &AppServices{ diff --git a/internal/core/data_initializer.go b/internal/core/data_initializer.go index c66bddf..9560aac 100644 --- a/internal/core/data_initializer.go +++ b/internal/core/data_initializer.go @@ -58,7 +58,7 @@ func (app *Application) initializeSystemPlans(ctx context.Context) error { } // 2. 为了方便查找, 将现有计划名放入一个 map - existingPlanMap := make(map[string]*models.Plan) + existingPlanMap := make(map[models.PlanName]*models.Plan) for i := range existingPlans { existingPlanMap[existingPlans[i].Name] = &existingPlans[i] } @@ -78,7 +78,7 @@ func (app *Application) initializeSystemPlans(ctx context.Context) error { // initializePeriodicSystemHealthCheckPlan 负责初始化 "周期性系统健康检查" 计划。 // 它会根据当前配置动态构建计划,并决定是创建新计划还是更新现有计划。 -func (app *Application) initializePeriodicSystemHealthCheckPlan(ctx context.Context, existingPlanMap map[string]*models.Plan) error { +func (app *Application) initializePeriodicSystemHealthCheckPlan(ctx context.Context, existingPlanMap map[models.PlanName]*models.Plan) error { appCtx, logger := logs.Trace(ctx, app.Ctx, "initializePeriodicSystemHealthCheckPlan") // 根据配置创建定时全量采集计划 @@ -175,7 +175,7 @@ func (app *Application) initializePeriodicSystemHealthCheckPlan(ctx context.Cont // initializeAlarmNotificationPlan 负责初始化 "告警通知发送" 计划。 // 它确保系统中存在一个每分钟执行的、用于发送告警通知的预定义计划。 -func (app *Application) initializeAlarmNotificationPlan(ctx context.Context, existingPlanMap map[string]*models.Plan) error { +func (app *Application) initializeAlarmNotificationPlan(ctx context.Context, existingPlanMap map[models.PlanName]*models.Plan) error { appCtx, logger := logs.Trace(ctx, app.Ctx, "initializeAlarmNotificationPlan") predefinedPlan := &models.Plan{