Compare commits
4 Commits
64c86de71e
...
4a70c1e839
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a70c1e839 | |||
| e75b3ee148 | |||
| cbcba09d40 | |||
| 4805e422f7 |
@@ -4,14 +4,13 @@
|
|||||||
package feed
|
package feed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"strconv"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/controller"
|
"git.huangwc.com/pig/pig-farm-controller/internal/controller"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/logs"
|
"git.huangwc.com/pig/pig-farm-controller/internal/logs"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/model"
|
"git.huangwc.com/pig/pig-farm-controller/internal/model"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/storage/repository"
|
"git.huangwc.com/pig/pig-farm-controller/internal/storage/repository"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Controller 饲料控制器
|
// Controller 饲料控制器
|
||||||
@@ -30,6 +29,26 @@ func NewController(feedPlanRepo repository.FeedPlanRepo) *Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete 删除饲料计划
|
||||||
|
func (c *Controller) Delete(ctx *gin.Context) {
|
||||||
|
// 获取路径参数中的计划ID
|
||||||
|
planIDStr := ctx.Param("id")
|
||||||
|
planID, err := strconv.ParseUint(planIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.InvalidParameterCode, "无效的计划ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用仓库删除计划
|
||||||
|
if err := c.feedPlanRepo.DeleteFeedingPlan(uint(planID)); err != nil {
|
||||||
|
c.logger.Error("删除计划失败: " + err.Error())
|
||||||
|
controller.SendErrorResponse(ctx, controller.InternalServerErrorCode, "删除计划失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.SendSuccessResponse(ctx, "删除计划成功", nil)
|
||||||
|
}
|
||||||
|
|
||||||
type ListPlansResponse struct {
|
type ListPlansResponse struct {
|
||||||
Plans []ListPlanResponseItem `json:"plans"`
|
Plans []ListPlanResponseItem `json:"plans"`
|
||||||
}
|
}
|
||||||
@@ -79,6 +98,22 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
|
|||||||
controller.SendSuccessResponse(ctx, "success", resp)
|
controller.SendSuccessResponse(ctx, "success", resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRequest 更新计划请求结构体
|
||||||
|
type UpdateRequest struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Type model.FeedingPlanType `json:"type"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
ScheduleCron *string `json:"scheduleCron"`
|
||||||
|
ExecutionLimit int `json:"executionLimit"`
|
||||||
|
ParentID *uint `json:"parentID"`
|
||||||
|
OrderInParent *int `json:"orderInParent"`
|
||||||
|
IsMaster bool `json:"isMaster"`
|
||||||
|
Steps []FeedingPlanStep `json:"steps"`
|
||||||
|
SubPlans []UpdateRequest `json:"subPlans"`
|
||||||
|
}
|
||||||
|
|
||||||
// DetailResponse 喂料计划主表
|
// DetailResponse 喂料计划主表
|
||||||
type DetailResponse struct {
|
type DetailResponse struct {
|
||||||
// ID 计划ID
|
// ID 计划ID
|
||||||
@@ -108,18 +143,6 @@ type DetailResponse struct {
|
|||||||
// OrderInParent 在父计划中的执行顺序
|
// OrderInParent 在父计划中的执行顺序
|
||||||
OrderInParent *int `json:"orderInParent"`
|
OrderInParent *int `json:"orderInParent"`
|
||||||
|
|
||||||
// IsMaster 是否为主计划(主计划可以包含子计划)
|
|
||||||
IsMaster bool `json:"isMaster"`
|
|
||||||
|
|
||||||
// CreatedAt 创建时间
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
|
|
||||||
// UpdatedAt 更新时间
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
|
|
||||||
// DeletedAt 删除时间(用于软删除)
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deletedAt"`
|
|
||||||
|
|
||||||
// Steps 计划步骤列表
|
// Steps 计划步骤列表
|
||||||
Steps []FeedingPlanStep `json:"steps"`
|
Steps []FeedingPlanStep `json:"steps"`
|
||||||
|
|
||||||
@@ -152,20 +175,139 @@ type FeedingPlanStep struct {
|
|||||||
|
|
||||||
// ExecutionLimit 步骤执行次数限制(0表示无限制)
|
// ExecutionLimit 步骤执行次数限制(0表示无限制)
|
||||||
ExecutionLimit int `json:"executionLimit"`
|
ExecutionLimit int `json:"executionLimit"`
|
||||||
|
|
||||||
// CreatedAt 创建时间
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
|
|
||||||
// UpdatedAt 更新时间
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
|
|
||||||
// DeletedAt 删除时间(用于软删除)
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deletedAt"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 获取饲料计划列细节
|
// Detail 获取饲料计划列细节
|
||||||
func (c *Controller) Detail(ctx *gin.Context) {
|
func (c *Controller) Detail(ctx *gin.Context) {
|
||||||
// TODO: 实现获取饲料计划列表的逻辑
|
// 获取路径参数中的计划ID
|
||||||
|
planIDStr := ctx.Param("id")
|
||||||
|
planID, err := strconv.ParseUint(planIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.InvalidParameterCode, "无效的计划ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
controller.SendSuccessResponse(ctx, "success", &DetailResponse{})
|
// 从仓库中获取计划详情
|
||||||
|
plan, err := c.feedPlanRepo.FindFeedingPlanByID(uint(planID))
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error("获取计划详情失败: " + err.Error())
|
||||||
|
controller.SendErrorResponse(ctx, controller.InternalServerErrorCode, "获取计划详情失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为响应结构体
|
||||||
|
resp := c.convertToDetailResponse(plan)
|
||||||
|
|
||||||
|
controller.SendSuccessResponse(ctx, "success", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 更新饲料计划
|
||||||
|
func (c *Controller) Update(ctx *gin.Context) {
|
||||||
|
var req UpdateRequest
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.InvalidParameterCode, "请求参数错误: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换请求结构体为模型
|
||||||
|
plan := c.convertToUpdateModel(&req)
|
||||||
|
|
||||||
|
// 调用仓库更新计划
|
||||||
|
if err := c.feedPlanRepo.UpdateFeedingPlan(plan); err != nil {
|
||||||
|
c.logger.Error("更新计划失败: " + err.Error())
|
||||||
|
controller.SendErrorResponse(ctx, controller.InternalServerErrorCode, "更新计划失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.SendSuccessResponse(ctx, "更新计划成功", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToUpdateModel 将更新请求结构体转换为数据库模型
|
||||||
|
func (c *Controller) convertToUpdateModel(req *UpdateRequest) *model.FeedingPlan {
|
||||||
|
plan := &model.FeedingPlan{
|
||||||
|
ID: req.ID,
|
||||||
|
Name: req.Name,
|
||||||
|
Description: req.Description,
|
||||||
|
Type: req.Type,
|
||||||
|
Enabled: req.Enabled,
|
||||||
|
ScheduleCron: req.ScheduleCron,
|
||||||
|
ExecutionLimit: req.ExecutionLimit,
|
||||||
|
ParentID: req.ParentID,
|
||||||
|
OrderInParent: req.OrderInParent,
|
||||||
|
Steps: make([]model.FeedingPlanStep, len(req.Steps)),
|
||||||
|
SubPlans: make([]model.FeedingPlan, len(req.SubPlans)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换步骤
|
||||||
|
for i, step := range req.Steps {
|
||||||
|
plan.Steps[i] = model.FeedingPlanStep{
|
||||||
|
ID: step.ID,
|
||||||
|
PlanID: step.PlanID,
|
||||||
|
StepOrder: step.StepOrder,
|
||||||
|
DeviceID: step.DeviceID,
|
||||||
|
TargetValue: step.TargetValue,
|
||||||
|
Action: step.Action,
|
||||||
|
ScheduleCron: step.ScheduleCron,
|
||||||
|
ExecutionLimit: step.ExecutionLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换子计划
|
||||||
|
for i, subReq := range req.SubPlans {
|
||||||
|
plan.SubPlans[i] = *c.convertToUpdateModel(&subReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
return plan
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToDetailResponse 将数据库模型转换为响应结构体
|
||||||
|
func (c *Controller) convertToDetailResponse(plan *model.FeedingPlan) *DetailResponse {
|
||||||
|
resp := &DetailResponse{
|
||||||
|
ID: plan.ID,
|
||||||
|
Name: plan.Name,
|
||||||
|
Description: plan.Description,
|
||||||
|
Type: plan.Type,
|
||||||
|
Enabled: plan.Enabled,
|
||||||
|
ScheduleCron: plan.ScheduleCron,
|
||||||
|
ExecutionLimit: plan.ExecutionLimit,
|
||||||
|
ParentID: plan.ParentID,
|
||||||
|
OrderInParent: plan.OrderInParent,
|
||||||
|
Steps: make([]FeedingPlanStep, len(plan.Steps)),
|
||||||
|
SubPlans: make([]DetailResponse, len(plan.SubPlans)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换步骤
|
||||||
|
for i, step := range plan.Steps {
|
||||||
|
resp.Steps[i] = FeedingPlanStep{
|
||||||
|
ID: step.ID,
|
||||||
|
PlanID: step.PlanID,
|
||||||
|
StepOrder: step.StepOrder,
|
||||||
|
DeviceID: step.DeviceID,
|
||||||
|
TargetValue: step.TargetValue,
|
||||||
|
Action: step.Action,
|
||||||
|
ScheduleCron: step.ScheduleCron,
|
||||||
|
ExecutionLimit: step.ExecutionLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换子计划
|
||||||
|
for i, subPlan := range plan.SubPlans {
|
||||||
|
// 递归转换子计划
|
||||||
|
subPlanModel := &model.FeedingPlan{
|
||||||
|
ID: subPlan.ID,
|
||||||
|
Name: subPlan.Name,
|
||||||
|
Description: subPlan.Description,
|
||||||
|
Type: subPlan.Type,
|
||||||
|
Enabled: subPlan.Enabled,
|
||||||
|
ScheduleCron: subPlan.ScheduleCron,
|
||||||
|
ExecutionLimit: subPlan.ExecutionLimit,
|
||||||
|
ParentID: subPlan.ParentID,
|
||||||
|
OrderInParent: subPlan.OrderInParent,
|
||||||
|
Steps: subPlan.Steps,
|
||||||
|
SubPlans: subPlan.SubPlans,
|
||||||
|
}
|
||||||
|
resp.SubPlans[i] = *c.convertToDetailResponse(subPlanModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ type FeedingPlan struct {
|
|||||||
// OrderInParent 在父计划中的执行顺序
|
// OrderInParent 在父计划中的执行顺序
|
||||||
OrderInParent *int `gorm:"column:order_in_parent" json:"order_in_parent,omitempty"`
|
OrderInParent *int `gorm:"column:order_in_parent" json:"order_in_parent,omitempty"`
|
||||||
|
|
||||||
// IsMaster 是否为主计划(主计划可以包含子计划)
|
|
||||||
IsMaster bool `gorm:"not null;default:false;column:is_master" json:"is_master"`
|
|
||||||
|
|
||||||
// CreatedAt 创建时间
|
// CreatedAt 创建时间
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ func (f *feedPlanRepo) UpdateFeedingPlan(feedingPlan *model.FeedingPlan) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空所有ID,包括子计划和步骤的ID
|
||||||
|
f.clearAllIDs(feedingPlan)
|
||||||
|
|
||||||
// 再重新创建更新后的计划
|
// 再重新创建更新后的计划
|
||||||
if err := f.createFeedingPlanWithTx(tx, feedingPlan); err != nil {
|
if err := f.createFeedingPlanWithTx(tx, feedingPlan); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -178,3 +181,22 @@ func (f *feedPlanRepo) createFeedingPlanWithTx(tx *gorm.DB, feedingPlan *model.F
|
|||||||
|
|
||||||
return nil
|
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])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user