实现根据区域ID或设备ID清空对应阈值告警任务
This commit is contained in:
@@ -142,3 +142,4 @@
|
||||
10. 实现区域阈值告警任务
|
||||
11. 实现区域阈值告警和设备阈值告警的增删改查
|
||||
12. 实现任务11应的八个web接口
|
||||
13. 实现根据区域ID或设备ID清空对应阈值告警任务
|
||||
@@ -49,11 +49,12 @@ type DeviceService interface {
|
||||
|
||||
// deviceService 是 DeviceService 接口的具体实现。
|
||||
type deviceService struct {
|
||||
ctx context.Context
|
||||
deviceRepo repository.DeviceRepository
|
||||
areaControllerRepo repository.AreaControllerRepository
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository
|
||||
deviceDomainSvc device.Service
|
||||
ctx context.Context
|
||||
deviceRepo repository.DeviceRepository
|
||||
areaControllerRepo repository.AreaControllerRepository
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository
|
||||
deviceDomainSvc device.Service
|
||||
thresholdAlarmService ThresholdAlarmService
|
||||
}
|
||||
|
||||
// NewDeviceService 创建一个新的 DeviceService 实例。
|
||||
@@ -63,13 +64,15 @@ func NewDeviceService(
|
||||
areaControllerRepo repository.AreaControllerRepository,
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository,
|
||||
deviceDomainSvc device.Service,
|
||||
thresholdAlarmService ThresholdAlarmService,
|
||||
) DeviceService {
|
||||
return &deviceService{
|
||||
ctx: ctx,
|
||||
deviceRepo: deviceRepo,
|
||||
areaControllerRepo: areaControllerRepo,
|
||||
deviceTemplateRepo: deviceTemplateRepo,
|
||||
deviceDomainSvc: deviceDomainSvc,
|
||||
ctx: ctx,
|
||||
deviceRepo: deviceRepo,
|
||||
areaControllerRepo: areaControllerRepo,
|
||||
deviceTemplateRepo: deviceTemplateRepo,
|
||||
deviceDomainSvc: deviceDomainSvc,
|
||||
thresholdAlarmService: thresholdAlarmService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +170,12 @@ func (s *deviceService) DeleteDevice(ctx context.Context, id uint) error {
|
||||
return err // 如果未找到,会返回 gorm.ErrRecordNotFound
|
||||
}
|
||||
|
||||
// TODO 这个应该用事务处理
|
||||
err = s.thresholdAlarmService.DeleteDeviceThresholdAlarmByDeviceID(serviceCtx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("删除设备阈值告警失败: %w", err)
|
||||
}
|
||||
|
||||
// 在删除前检查设备是否被任务使用
|
||||
inUse, err := s.deviceRepo.IsDeviceInUse(serviceCtx, id)
|
||||
if err != nil {
|
||||
@@ -287,6 +296,12 @@ func (s *deviceService) DeleteAreaController(ctx context.Context, id uint) error
|
||||
return err // 如果未找到,gorm会返回 ErrRecordNotFound
|
||||
}
|
||||
|
||||
// TODO 这个应该用事务处理
|
||||
err = s.thresholdAlarmService.DeleteAreaThresholdAlarmByAreaControllerID(serviceCtx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("删除区域阈值告警失败: %w", err)
|
||||
}
|
||||
|
||||
// 2. 检查是否被使用(业务逻辑)
|
||||
inUse, err := s.deviceRepo.IsAreaControllerInUse(serviceCtx, id)
|
||||
if err != nil {
|
||||
|
||||
@@ -34,6 +34,8 @@ type ThresholdAlarmService interface {
|
||||
GetDeviceThresholdAlarm(ctx context.Context, taskID int) (*dto.DeviceThresholdAlarmDTO, error)
|
||||
// DeleteDeviceThresholdAlarm 删除一个设备阈值告警。
|
||||
DeleteDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.DeleteDeviceThresholdAlarmDTO) error
|
||||
// DeleteDeviceThresholdAlarmByDeviceID 实现了根据设备ID删除一个设备下所有设备阈值告警的逻辑。
|
||||
DeleteDeviceThresholdAlarmByDeviceID(ctx context.Context, deviceID uint) error
|
||||
|
||||
// CreateAreaThresholdAlarm 创建一个区域阈值告警。
|
||||
CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error
|
||||
@@ -43,6 +45,8 @@ type ThresholdAlarmService interface {
|
||||
GetAreaThresholdAlarm(ctx context.Context, taskID int) (*dto.AreaThresholdAlarmDTO, error)
|
||||
// DeleteAreaThresholdAlarm 实现了删除一个区域阈值告警的逻辑。
|
||||
DeleteAreaThresholdAlarm(ctx context.Context, taskID int) error
|
||||
// DeleteAreaThresholdAlarmByAreaControllerID 实现了根据区域ID删除一个区域下所有区域阈值告警的逻辑。
|
||||
DeleteAreaThresholdAlarmByAreaControllerID(ctx context.Context, areaControllerID uint) error
|
||||
}
|
||||
|
||||
// thresholdAlarmService 是 ThresholdAlarmService 接口的具体实现。
|
||||
@@ -370,6 +374,76 @@ func (s *thresholdAlarmService) DeleteDeviceThresholdAlarm(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteDeviceThresholdAlarmByDeviceID 实现了根据设备ID删除一个设备下所有设备阈值告警的逻辑。
|
||||
func (s *thresholdAlarmService) DeleteDeviceThresholdAlarmByDeviceID(ctx context.Context, deviceID uint) error {
|
||||
serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeleteDeviceThresholdAlarmByDeviceID")
|
||||
tasks, err := s.planRepo.ListTasksByDeviceID(serviceCtx, deviceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取任务列表失败: %w", err)
|
||||
}
|
||||
device, err := s.deviceRepo.FindByID(serviceCtx, deviceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取设备 %d 失败: %w", deviceID, 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)
|
||||
}
|
||||
|
||||
deleteNums := []int{}
|
||||
for i, t := range plan.Tasks {
|
||||
for _, dt := range tasks {
|
||||
if t.ID == dt.ID && t.Type == models.TaskTypeDeviceThresholdCheck {
|
||||
deleteNums = append(deleteNums, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
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 == device.AreaControllerID {
|
||||
for ai, ae := range areaParams.ExcludeDeviceIDs {
|
||||
if ae == deviceID {
|
||||
areaParams.ExcludeDeviceIDs = append(areaParams.ExcludeDeviceIDs[:ai], areaParams.ExcludeDeviceIDs[ai+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
err = plan.Tasks[i].SaveParameters(areaParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("任务 %d: 保存参数失败: %w", t.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为了高效地判断一个索引是否需要被删除,先将 deleteNums 转换为一个 map。
|
||||
deleteMap := make(map[int]struct{}, len(deleteNums))
|
||||
for _, index := range deleteNums {
|
||||
deleteMap[index] = struct{}{}
|
||||
}
|
||||
|
||||
// 创建一个新的任务切片,只包含不需要删除的任务。
|
||||
newTasks := make([]models.Task, 0, len(plan.Tasks)-len(deleteNums))
|
||||
for i, t := range plan.Tasks {
|
||||
if _, found := deleteMap[i]; !found {
|
||||
newTasks = append(newTasks, t)
|
||||
}
|
||||
}
|
||||
plan.Tasks = newTasks
|
||||
|
||||
// 重新排序任务并更新计划
|
||||
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")
|
||||
@@ -555,3 +629,60 @@ func (s *thresholdAlarmService) DeleteAreaThresholdAlarm(ctx context.Context, ta
|
||||
_, err = s.planService.UpdatePlan(serviceCtx, plan, models.PlanTypeSystem)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteAreaThresholdAlarmByAreaControllerID 实现了根据区域ID删除一个区域下所有区域阈值告警的逻辑。
|
||||
func (s *thresholdAlarmService) DeleteAreaThresholdAlarmByAreaControllerID(ctx context.Context, areaControllerID uint) error {
|
||||
serviceCtx, logger := logs.Trace(ctx, s.ctx, "DeleteAreaThresholdAlarmByAreaControllerID")
|
||||
|
||||
// 1. 获取系统健康检查计划
|
||||
plan, err := s.planRepo.GetSystemPlanByName(serviceCtx, models.PlanNamePeriodicSystemHealthCheck)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取系统健康检查计划失败: %w", err)
|
||||
}
|
||||
if plan == nil {
|
||||
logger.Panicf("系统计划 %v 不存在", models.PlanNamePeriodicSystemHealthCheck)
|
||||
}
|
||||
|
||||
// 2. 收集所有与指定 areaControllerID 相关的区域阈值告警任务的索引
|
||||
var deleteIndices []int
|
||||
for i, t := range plan.Tasks {
|
||||
// 只关心区域阈值检查任务
|
||||
if t.Type != models.TaskTypeAreaCollectorThresholdCheck {
|
||||
continue
|
||||
}
|
||||
|
||||
var params task.AreaThresholdCheckParams
|
||||
if err := t.ParseParameters(¶ms); err != nil {
|
||||
return fmt.Errorf("任务 %d: 解析参数失败: %w", t.ID, err)
|
||||
}
|
||||
|
||||
// 如果 AreaControllerID 匹配,则记录其索引以待删除
|
||||
if params.AreaControllerID == areaControllerID {
|
||||
deleteIndices = append(deleteIndices, i)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到要删除的任务,则直接返回
|
||||
if len(deleteIndices) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 3. 使用 map 和新切片的方式安全地删除多个任务
|
||||
deleteMap := make(map[int]struct{}, len(deleteIndices))
|
||||
for _, index := range deleteIndices {
|
||||
deleteMap[index] = struct{}{}
|
||||
}
|
||||
|
||||
newTasks := make([]models.Task, 0, len(plan.Tasks)-len(deleteMap))
|
||||
for i, t := range plan.Tasks {
|
||||
if _, found := deleteMap[i]; !found {
|
||||
newTasks = append(newTasks, t)
|
||||
}
|
||||
}
|
||||
plan.Tasks = newTasks
|
||||
|
||||
// 4. 重新排序任务并更新计划
|
||||
plan.ReorderSteps()
|
||||
_, err = s.planService.UpdatePlan(serviceCtx, plan, models.PlanTypeSystem)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ type PlanRepository interface {
|
||||
StopPlanTransactionally(ctx context.Context, planID uint) error
|
||||
// UpdatePlanStateAfterExecution 更新计划执行后的状态(计数和状态)
|
||||
UpdatePlanStateAfterExecution(ctx context.Context, planID uint, newCount uint, newStatus models.PlanStatus) error
|
||||
// ListTasksByDeviceID 根据设备ID获取关联任务列表
|
||||
ListTasksByDeviceID(ctx context.Context, deviceID uint) ([]*models.Task, error)
|
||||
}
|
||||
|
||||
// gormPlanRepository 是 PlanRepository 的 GORM 实现
|
||||
@@ -878,3 +880,19 @@ func (r *gormPlanRepository) FindTaskByID(ctx context.Context, id int) (*models.
|
||||
}
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
func (r *gormPlanRepository) ListTasksByDeviceID(ctx context.Context, deviceID uint) ([]*models.Task, error) {
|
||||
repoCtx := logs.AddFuncName(ctx, r.ctx, "ListTasksByDeviceID")
|
||||
tasks := []*models.Task{}
|
||||
// 使用 Joins 方法来连接 tasks 表和 device_tasks 关联表,
|
||||
// 然后通过 Where 子句筛选出与指定 deviceID 关联的所有任务。
|
||||
err := r.db.WithContext(repoCtx).Joins("JOIN device_tasks ON device_tasks.task_id = tasks.id").
|
||||
Where("device_tasks.device_id = ?", deviceID).
|
||||
Find(&tasks).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user