2025-09-10 13:41:24 +08:00
|
|
|
|
package repository
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-09-10 14:15:03 +08:00
|
|
|
|
"sort"
|
|
|
|
|
|
|
2025-09-10 13:41:24 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/model"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// FeedPlanRepo 饲喂管理接口
|
|
|
|
|
|
type FeedPlanRepo interface {
|
|
|
|
|
|
|
|
|
|
|
|
// ListAllPlanIntroduction 获取所有计划简介
|
2025-09-10 14:15:03 +08:00
|
|
|
|
ListAllPlanIntroduction() ([]*model.FeedingPlan, error)
|
|
|
|
|
|
|
|
|
|
|
|
// FindFeedingPlanByID 根据ID获取计划详情
|
|
|
|
|
|
FindFeedingPlanByID(id uint) (*model.FeedingPlan, error)
|
|
|
|
|
|
|
|
|
|
|
|
// CreateFeedingPlan 创建饲料计划
|
|
|
|
|
|
CreateFeedingPlan(feedingPlan *model.FeedingPlan) error
|
2025-09-10 14:29:44 +08:00
|
|
|
|
|
|
|
|
|
|
// DeleteFeedingPlan 删除饲料计划及其所有子计划和步骤
|
|
|
|
|
|
DeleteFeedingPlan(id uint) error
|
2025-09-10 14:32:56 +08:00
|
|
|
|
|
|
|
|
|
|
// UpdateFeedingPlan 更新饲料计划,采用先删除再重新创建的方式
|
|
|
|
|
|
UpdateFeedingPlan(feedingPlan *model.FeedingPlan) error
|
2025-09-10 13:41:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type feedPlanRepo struct {
|
|
|
|
|
|
db *gorm.DB
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewFeedPlanRepo(db *gorm.DB) FeedPlanRepo {
|
|
|
|
|
|
return &feedPlanRepo{
|
|
|
|
|
|
db: db,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ListAllPlanIntroduction 获取所有计划简介
|
2025-09-10 14:15:03 +08:00
|
|
|
|
func (f *feedPlanRepo) ListAllPlanIntroduction() ([]*model.FeedingPlan, error) {
|
|
|
|
|
|
var plans []*model.FeedingPlan
|
2025-09-10 13:41:24 +08:00
|
|
|
|
err := f.db.Model(&model.FeedingPlan{}).
|
|
|
|
|
|
Select("id, name, description, type, enabled, schedule_cron").
|
|
|
|
|
|
Find(&plans).Error
|
|
|
|
|
|
return plans, err
|
|
|
|
|
|
}
|
2025-09-10 14:15:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
|
|
return f.db.Transaction(func(tx *gorm.DB) error {
|
|
|
|
|
|
return f.createFeedingPlanWithTx(tx, feedingPlan)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 14:32:56 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 15:00:29 +08:00
|
|
|
|
// 清空所有ID,包括子计划和步骤的ID
|
|
|
|
|
|
f.clearAllIDs(feedingPlan)
|
|
|
|
|
|
|
2025-09-10 14:32:56 +08:00
|
|
|
|
// 再重新创建更新后的计划
|
|
|
|
|
|
if err := f.createFeedingPlanWithTx(tx, feedingPlan); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 14:29:44 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 14:15:03 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 14:29:44 +08:00
|
|
|
|
// 处理子计划 - 重新填充子计划编号和父ID
|
2025-09-10 14:15:03 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
2025-09-10 15:00:29 +08:00
|
|
|
|
|
|
|
|
|
|
// 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])
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|