实现根据区域ID或设备ID清空对应阈值告警任务
This commit is contained in:
@@ -142,3 +142,4 @@
|
|||||||
10. 实现区域阈值告警任务
|
10. 实现区域阈值告警任务
|
||||||
11. 实现区域阈值告警和设备阈值告警的增删改查
|
11. 实现区域阈值告警和设备阈值告警的增删改查
|
||||||
12. 实现任务11应的八个web接口
|
12. 实现任务11应的八个web接口
|
||||||
|
13. 实现根据区域ID或设备ID清空对应阈值告警任务
|
||||||
@@ -49,11 +49,12 @@ type DeviceService interface {
|
|||||||
|
|
||||||
// deviceService 是 DeviceService 接口的具体实现。
|
// deviceService 是 DeviceService 接口的具体实现。
|
||||||
type deviceService struct {
|
type deviceService struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
deviceRepo repository.DeviceRepository
|
deviceRepo repository.DeviceRepository
|
||||||
areaControllerRepo repository.AreaControllerRepository
|
areaControllerRepo repository.AreaControllerRepository
|
||||||
deviceTemplateRepo repository.DeviceTemplateRepository
|
deviceTemplateRepo repository.DeviceTemplateRepository
|
||||||
deviceDomainSvc device.Service
|
deviceDomainSvc device.Service
|
||||||
|
thresholdAlarmService ThresholdAlarmService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDeviceService 创建一个新的 DeviceService 实例。
|
// NewDeviceService 创建一个新的 DeviceService 实例。
|
||||||
@@ -63,13 +64,15 @@ func NewDeviceService(
|
|||||||
areaControllerRepo repository.AreaControllerRepository,
|
areaControllerRepo repository.AreaControllerRepository,
|
||||||
deviceTemplateRepo repository.DeviceTemplateRepository,
|
deviceTemplateRepo repository.DeviceTemplateRepository,
|
||||||
deviceDomainSvc device.Service,
|
deviceDomainSvc device.Service,
|
||||||
|
thresholdAlarmService ThresholdAlarmService,
|
||||||
) DeviceService {
|
) DeviceService {
|
||||||
return &deviceService{
|
return &deviceService{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
deviceRepo: deviceRepo,
|
deviceRepo: deviceRepo,
|
||||||
areaControllerRepo: areaControllerRepo,
|
areaControllerRepo: areaControllerRepo,
|
||||||
deviceTemplateRepo: deviceTemplateRepo,
|
deviceTemplateRepo: deviceTemplateRepo,
|
||||||
deviceDomainSvc: deviceDomainSvc,
|
deviceDomainSvc: deviceDomainSvc,
|
||||||
|
thresholdAlarmService: thresholdAlarmService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +170,12 @@ func (s *deviceService) DeleteDevice(ctx context.Context, id uint) error {
|
|||||||
return err // 如果未找到,会返回 gorm.ErrRecordNotFound
|
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)
|
inUse, err := s.deviceRepo.IsDeviceInUse(serviceCtx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -287,6 +296,12 @@ func (s *deviceService) DeleteAreaController(ctx context.Context, id uint) error
|
|||||||
return err // 如果未找到,gorm会返回 ErrRecordNotFound
|
return err // 如果未找到,gorm会返回 ErrRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 这个应该用事务处理
|
||||||
|
err = s.thresholdAlarmService.DeleteAreaThresholdAlarmByAreaControllerID(serviceCtx, id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("删除区域阈值告警失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 检查是否被使用(业务逻辑)
|
// 2. 检查是否被使用(业务逻辑)
|
||||||
inUse, err := s.deviceRepo.IsAreaControllerInUse(serviceCtx, id)
|
inUse, err := s.deviceRepo.IsAreaControllerInUse(serviceCtx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ type ThresholdAlarmService interface {
|
|||||||
GetDeviceThresholdAlarm(ctx context.Context, taskID int) (*dto.DeviceThresholdAlarmDTO, error)
|
GetDeviceThresholdAlarm(ctx context.Context, taskID int) (*dto.DeviceThresholdAlarmDTO, error)
|
||||||
// DeleteDeviceThresholdAlarm 删除一个设备阈值告警。
|
// DeleteDeviceThresholdAlarm 删除一个设备阈值告警。
|
||||||
DeleteDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.DeleteDeviceThresholdAlarmDTO) error
|
DeleteDeviceThresholdAlarm(ctx context.Context, taskID int, req *dto.DeleteDeviceThresholdAlarmDTO) error
|
||||||
|
// DeleteDeviceThresholdAlarmByDeviceID 实现了根据设备ID删除一个设备下所有设备阈值告警的逻辑。
|
||||||
|
DeleteDeviceThresholdAlarmByDeviceID(ctx context.Context, deviceID uint) error
|
||||||
|
|
||||||
// CreateAreaThresholdAlarm 创建一个区域阈值告警。
|
// CreateAreaThresholdAlarm 创建一个区域阈值告警。
|
||||||
CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error
|
CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error
|
||||||
@@ -43,6 +45,8 @@ type ThresholdAlarmService interface {
|
|||||||
GetAreaThresholdAlarm(ctx context.Context, taskID int) (*dto.AreaThresholdAlarmDTO, error)
|
GetAreaThresholdAlarm(ctx context.Context, taskID int) (*dto.AreaThresholdAlarmDTO, error)
|
||||||
// DeleteAreaThresholdAlarm 实现了删除一个区域阈值告警的逻辑。
|
// DeleteAreaThresholdAlarm 实现了删除一个区域阈值告警的逻辑。
|
||||||
DeleteAreaThresholdAlarm(ctx context.Context, taskID int) error
|
DeleteAreaThresholdAlarm(ctx context.Context, taskID int) error
|
||||||
|
// DeleteAreaThresholdAlarmByAreaControllerID 实现了根据区域ID删除一个区域下所有区域阈值告警的逻辑。
|
||||||
|
DeleteAreaThresholdAlarmByAreaControllerID(ctx context.Context, areaControllerID uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// thresholdAlarmService 是 ThresholdAlarmService 接口的具体实现。
|
// thresholdAlarmService 是 ThresholdAlarmService 接口的具体实现。
|
||||||
@@ -370,6 +374,76 @@ func (s *thresholdAlarmService) DeleteDeviceThresholdAlarm(ctx context.Context,
|
|||||||
return err
|
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 实现了创建一个区域阈值告警的逻辑。
|
// CreateAreaThresholdAlarm 实现了创建一个区域阈值告警的逻辑。
|
||||||
func (s *thresholdAlarmService) CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error {
|
func (s *thresholdAlarmService) CreateAreaThresholdAlarm(ctx context.Context, req *dto.CreateAreaThresholdAlarmDTO) error {
|
||||||
serviceCtx, logger := logs.Trace(ctx, s.ctx, "CreateAreaThresholdAlarm")
|
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)
|
_, err = s.planService.UpdatePlan(serviceCtx, plan, models.PlanTypeSystem)
|
||||||
return err
|
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
|
StopPlanTransactionally(ctx context.Context, planID uint) error
|
||||||
// UpdatePlanStateAfterExecution 更新计划执行后的状态(计数和状态)
|
// UpdatePlanStateAfterExecution 更新计划执行后的状态(计数和状态)
|
||||||
UpdatePlanStateAfterExecution(ctx context.Context, planID uint, newCount uint, newStatus models.PlanStatus) error
|
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 实现
|
// gormPlanRepository 是 PlanRepository 的 GORM 实现
|
||||||
@@ -878,3 +880,19 @@ func (r *gormPlanRepository) FindTaskByID(ctx context.Context, id int) (*models.
|
|||||||
}
|
}
|
||||||
return &task, nil
|
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