package services import ( "beacon/models" "beacon/pkg/dao/mysql" "beacon/utils" "errors" "fmt" "go.uber.org/zap" "gorm.io/gorm" ) type CompositeCaseService struct { } // CreateCompositeCase 创建复合案例 func (s *CompositeCaseService) CreateCompositeCase(req *models.CreateCompositeCaseRequest) (*models.CompositeCase, error) { zap.L().Info("开始创建复合案例", zap.String("name", req.Name), zap.String("description", req.Description), zap.String("status", req.Status), zap.Int("steps_count", len(req.Steps))) // 开启事务 tx := dao.DB.Begin() if tx.Error != nil { zap.L().Error("创建复合案例失败 - 事务开启失败", zap.Error(tx.Error)) return nil, tx.Error } defer func() { if r := recover(); r != nil { zap.L().Error("创建复合案例失败 - 发生panic", zap.Any("panic", r)) tx.Rollback() } }() // 创建复合案例 compositeCase := &models.CompositeCase{ Name: req.Name, Description: req.Description, Status: req.Status, } if compositeCase.Status == "" { compositeCase.Status = "active" zap.L().Debug("设置默认状态", zap.String("status", "active")) } if err := tx.Create(compositeCase).Error; err != nil { zap.L().Error("创建复合案例失败 - 数据库创建失败", zap.Error(err)) tx.Rollback() return nil, fmt.Errorf("创建复合案例失败: %w", err) } zap.L().Info("复合案例创建成功", zap.Uint("id", compositeCase.ID), zap.String("name", compositeCase.Name)) // 创建步骤 if len(req.Steps) > 0 { zap.L().Info("开始创建步骤", zap.Int("steps_count", len(req.Steps))) var steps []models.CompositeCaseStep for _, stepReq := range req.Steps { activityName, _ := utils.GetActivityName(stepReq.StepType) step := models.CompositeCaseStep{ CompositeCaseID: compositeCase.ID, StepOrder: stepReq.StepOrder, StepName: stepReq.StepName, StepDescription: stepReq.StepDescription, StepType: stepReq.StepType, ActivityName: activityName, ParametersJson: stepReq.ParametersJson, IsRequired: stepReq.IsRequired, } steps = append(steps, step) } if err := tx.Create(&steps).Error; err != nil { zap.L().Error("创建复合案例步骤失败", zap.Uint("composite_case_id", compositeCase.ID), zap.Error(err)) tx.Rollback() return nil, fmt.Errorf("创建复合案例步骤失败: %w", err) } zap.L().Info("复合案例步骤创建成功", zap.Uint("composite_case_id", compositeCase.ID), zap.Int("created_steps_count", len(steps))) compositeCase.Steps = steps } tx.Commit() zap.L().Info("复合案例创建完成", zap.Uint("id", compositeCase.ID), zap.String("name", compositeCase.Name)) return compositeCase, nil } // GetCompositeCaseByID 根据ID获取复合案例 func (s *CompositeCaseService) GetCompositeCaseByID(id uint) (*models.CompositeCase, error) { zap.L().Debug("开始查询复合案例", zap.Uint("id", id)) var compositeCase models.CompositeCase err := dao.DB.Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step_order ASC") }).First(&compositeCase, id).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { zap.L().Warn("复合案例不存在", zap.Uint("id", id)) return nil, fmt.Errorf("复合案例不存在") } zap.L().Error("获取复合案例失败", zap.Uint("id", id), zap.Error(err)) return nil, fmt.Errorf("获取复合案例失败: %w", err) } zap.L().Debug("复合案例查询成功", zap.Uint("id", compositeCase.ID), zap.String("name", compositeCase.Name), zap.Int("steps_count", len(compositeCase.Steps))) return &compositeCase, nil } // UpdateCompositeCase 更新复合案例 func (s *CompositeCaseService) UpdateCompositeCase(id uint, req *models.UpdateCompositeCaseRequest) (*models.CompositeCase, error) { zap.L().Info("开始更新复合案例", zap.Uint("id", id)) // 开启事务 tx := dao.DB.Begin() if tx.Error != nil { zap.L().Error("更新复合案例失败 - 事务开启失败", zap.Uint("id", id), zap.Error(tx.Error)) return nil, tx.Error } defer func() { if r := recover(); r != nil { zap.L().Error("更新复合案例失败 - 发生panic", zap.Uint("id", id), zap.Any("panic", r)) tx.Rollback() } }() // 检查复合案例是否存在 var compositeCase models.CompositeCase if err := tx.First(&compositeCase, id).Error; err != nil { tx.Rollback() if errors.Is(err, gorm.ErrRecordNotFound) { zap.L().Warn("更新复合案例失败 - 复合案例不存在", zap.Uint("id", id)) return nil, fmt.Errorf("复合案例不存在") } zap.L().Error("更新复合案例失败 - 查询失败", zap.Uint("id", id), zap.Error(err)) return nil, fmt.Errorf("查询复合案例失败: %w", err) } // 更新基本信息 updates := make(map[string]interface{}) if req.Name != "" { updates["name"] = req.Name } if req.Description != "" { updates["description"] = req.Description } if req.Status != "" { updates["status"] = req.Status } if len(updates) > 0 { zap.L().Info("更新复合案例基本信息", zap.Uint("id", id), zap.Any("updates", updates)) if err := tx.Model(&compositeCase).Updates(updates).Error; err != nil { zap.L().Error("更新复合案例基本信息失败", zap.Uint("id", id), zap.Error(err)) tx.Rollback() return nil, fmt.Errorf("更新复合案例失败: %w", err) } } // 更新步骤 if req.Steps != nil { zap.L().Info("开始更新复合案例步骤", zap.Uint("id", id), zap.Int("new_steps_count", len(req.Steps))) // 删除现有步骤 if err := tx.Where("composite_case_id = ?", id).Delete(&models.CompositeCaseStep{}).Error; err != nil { zap.L().Error("删除现有步骤失败", zap.Uint("id", id), zap.Error(err)) tx.Rollback() return nil, fmt.Errorf("删除现有步骤失败: %w", err) } // 创建新步骤 if len(req.Steps) > 0 { var steps []models.CompositeCaseStep for _, stepReq := range req.Steps { activityName, _ := utils.GetActivityName(stepReq.StepType) step := models.CompositeCaseStep{ CompositeCaseID: id, StepOrder: stepReq.StepOrder, StepName: stepReq.StepName, StepDescription: stepReq.StepDescription, StepType: stepReq.StepType, ActivityName: activityName, ParametersJson: stepReq.ParametersJson, IsRequired: stepReq.IsRequired, } steps = append(steps, step) } if err := tx.Create(&steps).Error; err != nil { zap.L().Error("创建新步骤失败", zap.Uint("id", id), zap.Error(err)) tx.Rollback() return nil, fmt.Errorf("创建新步骤失败: %w", err) } zap.L().Info("新步骤创建成功", zap.Uint("id", id), zap.Int("created_steps_count", len(steps))) } } tx.Commit() zap.L().Info("复合案例更新完成", zap.Uint("id", id)) // 重新查询并返回更新后的数据 return s.GetCompositeCaseByID(id) } // DeleteCompositeCase 删除复合案例 func (s *CompositeCaseService) DeleteCompositeCase(id uint) error { zap.L().Info("开始删除复合案例", zap.Uint("id", id)) // 开启事务 tx := dao.DB.Begin() if tx.Error != nil { zap.L().Error("删除复合案例失败 - 事务开启失败", zap.Uint("id", id), zap.Error(tx.Error)) return tx.Error } defer func() { if r := recover(); r != nil { zap.L().Error("删除复合案例失败 - 发生panic", zap.Uint("id", id), zap.Any("panic", r)) tx.Rollback() } }() // 检查复合案例是否存在 var compositeCase models.CompositeCase if err := tx.First(&compositeCase, id).Error; err != nil { tx.Rollback() if errors.Is(err, gorm.ErrRecordNotFound) { zap.L().Warn("删除复合案例失败 - 复合案例不存在", zap.Uint("id", id)) return fmt.Errorf("复合案例不存在") } zap.L().Error("删除复合案例失败 - 查询失败", zap.Uint("id", id), zap.Error(err)) return fmt.Errorf("查询复合案例失败: %w", err) } zap.L().Info("找到复合案例,开始删除", zap.Uint("id", id), zap.String("name", compositeCase.Name)) // 删除关联的步骤 if err := tx.Where("composite_case_id = ?", id).Delete(&models.CompositeCaseStep{}).Error; err != nil { zap.L().Error("删除复合案例步骤失败", zap.Uint("id", id), zap.Error(err)) tx.Rollback() return fmt.Errorf("删除复合案例步骤失败: %w", err) } zap.L().Debug("复合案例步骤删除成功", zap.Uint("id", id)) // 删除复合案例 if err := tx.Delete(&compositeCase).Error; err != nil { zap.L().Error("删除复合案例失败", zap.Uint("id", id), zap.Error(err)) tx.Rollback() return fmt.Errorf("删除复合案例失败: %w", err) } tx.Commit() zap.L().Info("复合案例删除完成", zap.Uint("id", id), zap.String("name", compositeCase.Name)) return nil } // ListCompositeCases 获取复合案例列表 func (s *CompositeCaseService) ListCompositeCases(page, pageSize int, status string) ([]models.CompositeCase, int64, error) { zap.L().Info("开始查询复合案例列表", zap.Int("page", page), zap.Int("page_size", pageSize), zap.String("status", status)) var compositeCases []models.CompositeCase var total int64 query := dao.DB.Model(&models.CompositeCase{}) if status != "" { query = query.Where("status = ?", status) zap.L().Debug("添加状态过滤条件", zap.String("status", status)) } // 获取总数 if err := query.Count(&total).Error; err != nil { zap.L().Error("获取复合案例总数失败", zap.Error(err)) return nil, 0, fmt.Errorf("获取复合案例总数失败: %w", err) } zap.L().Debug("查询到复合案例总数", zap.Int64("total", total)) // 分页查询 offset := (page - 1) * pageSize err := query.Preload("Steps", func(db *gorm.DB) *gorm.DB { return db.Order("step_order ASC") }).Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&compositeCases).Error if err != nil { zap.L().Error("获取复合案例列表失败", zap.Error(err)) return nil, 0, fmt.Errorf("获取复合案例列表失败: %w", err) } zap.L().Info("复合案例列表查询成功", zap.Int("returned_count", len(compositeCases)), zap.Int64("total_count", total)) return compositeCases, total, nil }