package services import ( "beacon/models" "beacon/pkg/dao/mysql" "beacon/utils" "encoding/json" "fmt" "go.uber.org/zap" ) 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.BeginTransaction() 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 err := dao.CreateCompositeCase(tx, compositeCase); 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: fixParametersJson(stepReq.ParametersJson), IsRequired: stepReq.IsRequired, } steps = append(steps, step) } if err := dao.CreateCompositeCaseSteps(tx, steps); 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)) compositeCase, err := dao.GetCompositeCaseByID(id) if err != nil { zap.L().Error("获取复合案例失败", zap.Uint("id", id), zap.Error(err)) return nil, 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.BeginTransaction() 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() } }() // 检查复合案例是否存在 if _, err := dao.ExistsCompositeCase(tx, id); err != nil { tx.Rollback() zap.L().Warn("更新复合案例失败 - 复合案例不存在", zap.Uint("id", id)) return nil, 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 := dao.UpdateCompositeCase(tx, id, updates); 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 := dao.DeleteCompositeCaseStepsByCompositeCaseID(tx, id); 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: fixParametersJson(stepReq.ParametersJson), IsRequired: stepReq.IsRequired, } steps = append(steps, step) } if err := dao.CreateCompositeCaseSteps(tx, steps); 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) } func fixParametersJson(jsonStr string) string { var params map[string]interface{} if err := json.Unmarshal([]byte(jsonStr), ¶ms); err != nil { // Not a valid json string, return as is. return jsonStr } if rb, ok := params["request_body"]; ok { if rbs, ok := rb.(string); ok && rbs == "{" { params["request_body"] = "{}" } } fixedJSONBytes, err := json.Marshal(params) if err != nil { // Failed to marshal back, return original. return jsonStr } return string(fixedJSONBytes) } // DeleteCompositeCase 删除复合案例 func (s *CompositeCaseService) DeleteCompositeCase(id uint) error { zap.L().Info("开始删除复合案例", zap.Uint("id", id)) // 开启事务 tx := dao.BeginTransaction() 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() } }() // 检查复合案例是否存在 compositeCase, err := dao.ExistsCompositeCase(tx, id) if err != nil { tx.Rollback() zap.L().Warn("删除复合案例失败", zap.Uint("id", id), zap.Error(err)) return err } zap.L().Info("找到复合案例,开始删除", zap.Uint("id", id), zap.String("name", compositeCase.Name)) // 删除关联的步骤 if err := dao.DeleteCompositeCaseStepsByCompositeCaseID(tx, id); 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 := dao.DeleteCompositeCase(tx, id); 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)) compositeCases, total, err := dao.ListCompositeCases(page, pageSize, status) if err != nil { zap.L().Error("获取复合案例列表失败", zap.Error(err)) return nil, 0, err } zap.L().Info("复合案例列表查询成功", zap.Int("returned_count", len(compositeCases)), zap.Int64("total_count", total)) return compositeCases, total, nil }