1.注册饲喂计划相关路由

2. 实现create接口
This commit is contained in:
2025-09-10 15:13:31 +08:00
parent 4a70c1e839
commit 9944340d17
3 changed files with 159 additions and 29 deletions

View File

@@ -69,7 +69,16 @@ type API struct {
// NewAPI 创建并返回一个新的API实例 // NewAPI 创建并返回一个新的API实例
// 初始化Gin引擎和相关配置 // 初始化Gin引擎和相关配置
func NewAPI(cfg *config.Config, userRepo repository.UserRepo, operationHistoryRepo repository.OperationHistoryRepo, deviceControlRepo repository.DeviceControlRepo, deviceRepo repository.DeviceRepo, websocketManager *websocket.Manager, heartbeatService *service.HeartbeatService, deviceStatusPool *service.DeviceStatusPool) *API { func NewAPI(cfg *config.Config,
userRepo repository.UserRepo,
operationHistoryRepo repository.OperationHistoryRepo,
deviceControlRepo repository.DeviceControlRepo,
deviceRepo repository.DeviceRepo,
feedRepo repository.FeedPlanRepo,
websocketManager *websocket.Manager,
heartbeatService *service.HeartbeatService,
deviceStatusPool *service.DeviceStatusPool,
) *API {
// 设置Gin为发布模式 // 设置Gin为发布模式
gin.SetMode(gin.DebugMode) gin.SetMode(gin.DebugMode)
@@ -103,7 +112,7 @@ func NewAPI(cfg *config.Config, userRepo repository.UserRepo, operationHistoryRe
deviceController := device.NewController(deviceControlRepo, deviceRepo, websocketManager, heartbeatService, deviceStatusPool) deviceController := device.NewController(deviceControlRepo, deviceRepo, websocketManager, heartbeatService, deviceStatusPool)
// 创建饲喂管理控制器 // 创建饲喂管理控制器
feedController := feed.NewController() feedController := feed.NewController(feedRepo)
// 创建远程控制控制器 // 创建远程控制控制器
remoteController := remote.NewController(websocketManager) remoteController := remote.NewController(websocketManager)
@@ -235,6 +244,9 @@ func (a *API) setupRoutes() {
{ {
feedGroup.GET("/plan/list", a.feedController.ListPlans) feedGroup.GET("/plan/list", a.feedController.ListPlans)
feedGroup.GET("/plan/detail", a.feedController.Detail) feedGroup.GET("/plan/detail", a.feedController.Detail)
feedGroup.POST("/plan/create", a.feedController.Create)
feedGroup.POST("/plan/update", a.feedController.Update)
feedGroup.POST("/plan/delete", a.feedController.Delete)
} }
// 远程控制相关路由 // 远程控制相关路由

View File

@@ -29,6 +29,100 @@ func NewController(feedPlanRepo repository.FeedPlanRepo) *Controller {
} }
} }
// CreateRequest 创建计划请求结构体
type CreateRequest struct {
// Name 计划名称
Name string `json:"name"`
// Description 计划描述
Description string `json:"description"`
// Type 计划类型(手动触发/自动触发)
Type model.FeedingPlanType `json:"type"`
// Enabled 是否启用
Enabled bool `json:"enabled"`
// ScheduleCron 定时任务表达式(仅当Type为auto时有效)
ScheduleCron *string `json:"scheduleCron"`
// ExecutionLimit 执行次数限制(0表示无限制仅当Type为auto时有效)
ExecutionLimit int `json:"executionLimit"`
// ParentID 父计划ID用于支持子计划结构
ParentID *uint `json:"parentID"`
// OrderInParent 在父计划中的执行顺序
OrderInParent *int `json:"orderInParent"`
// IsMaster 是否为主计划(主计划可以包含子计划)
IsMaster bool `json:"isMaster"`
// Steps 计划步骤列表
Steps []FeedingPlanStep `json:"steps"`
// SubPlans 子计划列表
SubPlans []CreateRequest `json:"subPlans"`
}
// Create 创建饲料计划
func (c *Controller) Create(ctx *gin.Context) {
var req CreateRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorResponse(ctx, controller.InvalidParameterCode, "请求参数错误: "+err.Error())
return
}
// 转换请求结构体为模型
plan := c.convertToCreateModel(&req)
// 调用仓库创建计划
if err := c.feedPlanRepo.CreateFeedingPlan(plan); err != nil {
c.logger.Error("创建计划失败: " + err.Error())
controller.SendErrorResponse(ctx, controller.InternalServerErrorCode, "创建计划失败")
return
}
controller.SendSuccessResponse(ctx, "创建计划成功", nil)
}
// convertToCreateModel 将创建请求结构体转换为数据库模型
func (c *Controller) convertToCreateModel(req *CreateRequest) *model.FeedingPlan {
plan := &model.FeedingPlan{
Name: req.Name,
Description: req.Description,
Type: req.Type,
Enabled: req.Enabled,
ScheduleCron: req.ScheduleCron,
ExecutionLimit: req.ExecutionLimit,
ParentID: req.ParentID,
OrderInParent: req.OrderInParent,
}
// 转换步骤
plan.Steps = make([]model.FeedingPlanStep, len(req.Steps))
for i, step := range req.Steps {
plan.Steps[i] = model.FeedingPlanStep{
// ID在创建时不需要设置
// PlanID会在创建过程中自动设置
StepOrder: step.StepOrder,
DeviceID: step.DeviceID,
TargetValue: step.TargetValue,
Action: step.Action,
ScheduleCron: step.ScheduleCron,
ExecutionLimit: step.ExecutionLimit,
}
}
// 转换子计划
plan.SubPlans = make([]model.FeedingPlan, len(req.SubPlans))
for i, subReq := range req.SubPlans {
plan.SubPlans[i] = *c.convertToCreateModel(&subReq)
}
return plan
}
// Delete 删除饲料计划 // Delete 删除饲料计划
func (c *Controller) Delete(ctx *gin.Context) { func (c *Controller) Delete(ctx *gin.Context) {
// 获取路径参数中的计划ID // 获取路径参数中的计划ID
@@ -100,17 +194,40 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
// UpdateRequest 更新计划请求结构体 // UpdateRequest 更新计划请求结构体
type UpdateRequest struct { type UpdateRequest struct {
// ID 计划ID
ID uint `json:"id"` ID uint `json:"id"`
// Name 计划名称
Name string `json:"name"` Name string `json:"name"`
// Description 计划描述
Description string `json:"description"` Description string `json:"description"`
// Type 计划类型(手动触发/自动触发)
Type model.FeedingPlanType `json:"type"` Type model.FeedingPlanType `json:"type"`
// Enabled 是否启用
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
// ScheduleCron 定时任务表达式(仅当Type为auto时有效)
ScheduleCron *string `json:"scheduleCron"` ScheduleCron *string `json:"scheduleCron"`
// ExecutionLimit 执行次数限制(0表示无限制仅当Type为auto时有效)
ExecutionLimit int `json:"executionLimit"` ExecutionLimit int `json:"executionLimit"`
// ParentID 父计划ID用于支持子计划结构
ParentID *uint `json:"parentID"` ParentID *uint `json:"parentID"`
// OrderInParent 在父计划中的执行顺序
OrderInParent *int `json:"orderInParent"` OrderInParent *int `json:"orderInParent"`
// IsMaster 是否为主计划(主计划可以包含子计划)
IsMaster bool `json:"isMaster"` IsMaster bool `json:"isMaster"`
// Steps 计划步骤列表
Steps []FeedingPlanStep `json:"steps"` Steps []FeedingPlanStep `json:"steps"`
// SubPlans 子计划列表
SubPlans []UpdateRequest `json:"subPlans"` SubPlans []UpdateRequest `json:"subPlans"`
} }
@@ -293,20 +410,7 @@ func (c *Controller) convertToDetailResponse(plan *model.FeedingPlan) *DetailRes
// 转换子计划 // 转换子计划
for i, subPlan := range plan.SubPlans { for i, subPlan := range plan.SubPlans {
// 递归转换子计划 // 递归转换子计划
subPlanModel := &model.FeedingPlan{ resp.SubPlans[i] = *c.convertToDetailResponse(&subPlan)
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 return resp

View File

@@ -40,6 +40,9 @@ type Application struct {
// DeviceRepo 设备仓库实例 // DeviceRepo 设备仓库实例
DeviceRepo repository.DeviceRepo DeviceRepo repository.DeviceRepo
// FeedPlanRepo 投喂计划仓库实例
FeedPlanRepo repository.FeedPlanRepo
// WebsocketManager WebSocket管理器 // WebsocketManager WebSocket管理器
WebsocketManager *websocket.Manager WebsocketManager *websocket.Manager
@@ -97,6 +100,8 @@ func (app *Application) Start() error {
// 初始化设备仓库 // 初始化设备仓库
app.DeviceRepo = repository.NewDeviceRepo(app.Storage.GetDB()) app.DeviceRepo = repository.NewDeviceRepo(app.Storage.GetDB())
app.FeedPlanRepo = repository.NewFeedPlanRepo(app.Storage.GetDB())
// 初始化设备状态池 // 初始化设备状态池
app.DeviceStatusPool = service.NewDeviceStatusPool() app.DeviceStatusPool = service.NewDeviceStatusPool()
@@ -109,7 +114,16 @@ func (app *Application) Start() error {
app.HeartbeatService = service.NewHeartbeatService(app.WebsocketManager, app.DeviceStatusPool, app.DeviceRepo, app.Config) app.HeartbeatService = service.NewHeartbeatService(app.WebsocketManager, app.DeviceStatusPool, app.DeviceRepo, app.Config)
// 初始化API组件 // 初始化API组件
app.API = api.NewAPI(app.Config, app.UserRepo, app.OperationHistoryRepo, app.DeviceControlRepo, app.DeviceRepo, app.WebsocketManager, app.HeartbeatService, app.DeviceStatusPool) app.API = api.NewAPI(app.Config,
app.UserRepo,
app.OperationHistoryRepo,
app.DeviceControlRepo,
app.DeviceRepo,
app.FeedPlanRepo,
app.WebsocketManager,
app.HeartbeatService,
app.DeviceStatusPool,
)
// 初始化任务执行器组件(使用5个工作协程) // 初始化任务执行器组件(使用5个工作协程)
app.TaskExecutor = task.NewExecutor(5) app.TaskExecutor = task.NewExecutor(5)