From 287c27a5ab1516c0595910d2665df07a4a24bdbd Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Sat, 13 Sep 2025 20:13:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=88=9B=E5=BB=BA=E8=AE=A1?= =?UTF-8?q?=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/infra/repository/plan_repository.go | 83 +++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/internal/infra/repository/plan_repository.go b/internal/infra/repository/plan_repository.go index 8667338..d38d523 100644 --- a/internal/infra/repository/plan_repository.go +++ b/internal/infra/repository/plan_repository.go @@ -10,9 +10,12 @@ import ( // 定义仓库层可导出的公共错误 var ( - ErrUpdateWithInvalidRoot = errors.New("更新操作的目标根计划无效或ID为0") - ErrNewSubPlanInUpdate = errors.New("计划树中包含一个ID为0的新子计划,更新操作只允许关联已存在的计划") - ErrNodeDoesNotExist = errors.New("计划树中包含一个或多个在数据库中不存在的计划") + ErrUpdateWithInvalidRoot = errors.New("更新操作的目标根计划无效或ID为0") + ErrNewSubPlanInUpdate = errors.New("计划树中包含一个ID为0的新子计划,更新操作只允许关联已存在的计划") + ErrNodeDoesNotExist = errors.New("计划树中包含一个或多个在数据库中不存在的计划") + ErrCreateWithNonZeroID = errors.New("创建操作的计划ID必须为0") + ErrSubPlanIDIsZeroOnCreate = errors.New("子计划ID为0,创建操作只允许关联已存在的计划") + ErrMixedContent = errors.New("计划不能同时包含任务和子计划") ) // PlanRepository 定义了与计划模型相关的数据库操作接口 @@ -24,6 +27,8 @@ type PlanRepository interface { GetBasicPlanByID(id uint) (*models.Plan, error) // GetPlanByID 根据ID获取计划,包含子计划和任务详情 GetPlanByID(id uint) (*models.Plan, error) + // Create 创建一个新的计划 + Create(plan *models.Plan) error // UpdatePlan 更新计划,包括子计划和任务 UpdatePlan(plan *models.Plan) error } @@ -107,6 +112,76 @@ func (r *gormPlanRepository) GetPlanByID(id uint) (*models.Plan, error) { return &plan, nil } +// Create 创建一个新的计划 +func (r *gormPlanRepository) Create(plan *models.Plan) error { + return r.db.Transaction(func(tx *gorm.DB) error { + // 1. 前置校验 + if plan.ID != 0 { + return ErrCreateWithNonZeroID + } + + // 检查是否同时包含任务和子计划 + if len(plan.Tasks) > 0 && len(plan.SubPlans) > 0 { + return ErrMixedContent + } + + // 如果是子计划类型,验证所有子计划是否存在且ID不为0 + if plan.ContentType == models.PlanContentTypeSubPlans { + childIDsToValidate := make(map[uint]bool) + for _, subPlanLink := range plan.SubPlans { + if subPlanLink.ChildPlan == nil || subPlanLink.ChildPlan.ID == 0 { + return ErrSubPlanIDIsZeroOnCreate + } + childIDsToValidate[subPlanLink.ChildPlan.ID] = true + } + + var ids []uint + for id := range childIDsToValidate { + ids = append(ids, id) + } + + if len(ids) > 0 { + var count int64 + if err := tx.Model(&models.Plan{}).Where("id IN ?", ids).Count(&count).Error; err != nil { + return fmt.Errorf("验证子计划存在性失败: %w", err) + } + if int(count) != len(ids) { + return ErrNodeDoesNotExist + } + } + } + + // 2. 创建根计划 + // GORM 会自动处理关联的 Tasks (如果 ContentType 是 tasks 且 Task.ID 为 0) + if err := tx.Create(plan).Error; err != nil { + return err + } + + // 3. 处理子计划关联 (如果 ContentType 是 sub_plans) + // GORM 不会自动创建 SubPlan 关联记录,需要手动处理 + if plan.ContentType == models.PlanContentTypeSubPlans { + // 收集所有 SubPlan 关联,设置 ParentPlanID + var subPlanLinksToCreate []models.SubPlan + for i := range plan.SubPlans { + plan.SubPlans[i].ParentPlanID = plan.ID // 设置父计划ID + // 确保 ChildPlanID 被正确设置,因为 ChildPlan 对象可能只在内存中 + if plan.SubPlans[i].ChildPlanID == 0 && plan.SubPlans[i].ChildPlan != nil { + plan.SubPlans[i].ChildPlanID = plan.SubPlans[i].ChildPlan.ID + } + subPlanLinksToCreate = append(subPlanLinksToCreate, plan.SubPlans[i]) + } + + // 批量创建 SubPlan 关联记录 + if len(subPlanLinksToCreate) > 0 { + if err := tx.CreateInBatches(subPlanLinksToCreate, 100).Error; err != nil { // 批量大小100 + return err + } + } + } + return nil + }) +} + // UpdatePlan 是更新计划的公共入口点 func (r *gormPlanRepository) UpdatePlan(plan *models.Plan) error { return r.db.Transaction(func(tx *gorm.DB) error { @@ -299,3 +374,5 @@ func (r *gormPlanRepository) reconcileSubPlans(tx *gorm.DB, plan *models.Plan) e } return nil } + +/// ABC