package repository import ( "sort" "git.huangwc.com/pig/pig-farm-controller/internal/model" "gorm.io/gorm" ) // FeedPlanRepo 饲喂管理接口 type FeedPlanRepo interface { // ListAllPlanIntroduction 获取所有计划简介 ListAllPlanIntroduction() ([]*model.FeedingPlan, error) // FindFeedingPlanByID 根据ID获取计划详情 FindFeedingPlanByID(id uint) (*model.FeedingPlan, error) // CreateFeedingPlan 创建饲料计划 CreateFeedingPlan(feedingPlan *model.FeedingPlan) error // DeleteFeedingPlan 删除饲料计划及其所有子计划和步骤 DeleteFeedingPlan(id uint) error // UpdateFeedingPlan 更新饲料计划,采用先删除再重新创建的方式 UpdateFeedingPlan(feedingPlan *model.FeedingPlan) error } type feedPlanRepo struct { db *gorm.DB } func NewFeedPlanRepo(db *gorm.DB) FeedPlanRepo { return &feedPlanRepo{ db: db, } } // ListAllPlanIntroduction 获取所有计划简介 func (f *feedPlanRepo) ListAllPlanIntroduction() ([]*model.FeedingPlan, error) { var plans []*model.FeedingPlan err := f.db.Model(&model.FeedingPlan{}). Select("id, name, description, type, enabled, schedule_cron"). Find(&plans).Error return plans, err } // FindFeedingPlanByID 根据ID获取计划详情 func (f *feedPlanRepo) FindFeedingPlanByID(feedingPlanID uint) (*model.FeedingPlan, error) { var plan model.FeedingPlan err := f.db.Where("id = ?", feedingPlanID). Preload("Steps"). Preload("SubPlans"). First(&plan).Error if err != nil { return nil, err } return &plan, nil } // CreateFeedingPlan 创建饲料计划,包括步骤和子计划 func (f *feedPlanRepo) CreateFeedingPlan(feedingPlan *model.FeedingPlan) error { // 清空所有ID,确保创建新记录 f.clearAllIDs(feedingPlan) return f.db.Transaction(func(tx *gorm.DB) error { return f.createFeedingPlanWithTx(tx, feedingPlan) }) } // UpdateFeedingPlan 更新饲料计划,采用先删除再重新创建的方式 func (f *feedPlanRepo) UpdateFeedingPlan(feedingPlan *model.FeedingPlan) error { // 检查计划是否存在 _, err := f.FindFeedingPlanByID(feedingPlan.ID) if err != nil { return err } return f.db.Transaction(func(tx *gorm.DB) error { // 先删除原有的计划 if err := f.deleteFeedingPlanWithTx(tx, feedingPlan.ID); err != nil { return err } // 清空所有ID,包括子计划和步骤的ID f.clearAllIDs(feedingPlan) // 再重新创建更新后的计划 if err := f.createFeedingPlanWithTx(tx, feedingPlan); err != nil { return err } return nil }) } // DeleteFeedingPlan 删除饲料计划及其所有子计划和步骤 func (f *feedPlanRepo) DeleteFeedingPlan(id uint) error { return f.db.Transaction(func(tx *gorm.DB) error { // 递归删除计划及其所有子计划 if err := f.deleteFeedingPlanWithTx(tx, id); err != nil { return err } return nil }) } // deleteFeedingPlanWithTx 在事务中递归删除饲料计划 func (f *feedPlanRepo) deleteFeedingPlanWithTx(tx *gorm.DB, id uint) error { // 先查找计划及其子计划 var plan model.FeedingPlan if err := tx.Where("id = ?", id).Preload("SubPlans").First(&plan).Error; err != nil { return err } // 递归删除所有子计划 for _, subPlan := range plan.SubPlans { if err := f.deleteFeedingPlanWithTx(tx, subPlan.ID); err != nil { return err } } // 删除该计划的所有步骤 if err := tx.Where("plan_id = ?", id).Delete(&model.FeedingPlanStep{}).Error; err != nil { return err } // 删除计划本身 if err := tx.Delete(&model.FeedingPlan{}, id).Error; err != nil { return err } return nil } // createFeedingPlanWithTx 在事务中递归创建饲料计划 func (f *feedPlanRepo) createFeedingPlanWithTx(tx *gorm.DB, feedingPlan *model.FeedingPlan) error { // 先创建计划主体 if err := tx.Create(feedingPlan).Error; err != nil { return err } // 处理步骤 - 先按现有顺序排序,再重新分配从0开始的连续编号 sort.Slice(feedingPlan.Steps, func(i, j int) bool { return feedingPlan.Steps[i].StepOrder < feedingPlan.Steps[j].StepOrder }) // 重新填充步骤编号 for i := range feedingPlan.Steps { feedingPlan.Steps[i].StepOrder = i feedingPlan.Steps[i].PlanID = feedingPlan.ID } // 如果有步骤,批量创建步骤 if len(feedingPlan.Steps) > 0 { if err := tx.Create(&feedingPlan.Steps).Error; err != nil { return err } } // 处理子计划 - 重新填充子计划编号和父ID sort.Slice(feedingPlan.SubPlans, func(i, j int) bool { // 如果OrderInParent为nil,放在最后 if feedingPlan.SubPlans[i].OrderInParent == nil { return false } if feedingPlan.SubPlans[j].OrderInParent == nil { return true } return *feedingPlan.SubPlans[i].OrderInParent < *feedingPlan.SubPlans[j].OrderInParent }) // 重新填充子计划编号和父ID for i := range feedingPlan.SubPlans { order := i feedingPlan.SubPlans[i].OrderInParent = &order feedingPlan.SubPlans[i].ParentID = &feedingPlan.ID // 递归创建子计划 if err := f.createFeedingPlanWithTx(tx, &feedingPlan.SubPlans[i]); err != nil { return err } } return nil } // clearAllIDs 清空计划及其子计划和步骤的所有ID func (f *feedPlanRepo) clearAllIDs(plan *model.FeedingPlan) { // 清空计划ID plan.ID = 0 // 清空所有步骤的ID和关联的计划ID for i := range plan.Steps { plan.Steps[i].ID = 0 plan.Steps[i].PlanID = 0 } // 清空所有子计划的ID和关联的父计划ID,并递归清空子计划的ID for i := range plan.SubPlans { plan.SubPlans[i].ID = 0 plan.SubPlans[i].ParentID = nil f.clearAllIDs(&plan.SubPlans[i]) } }