ManualControl
This commit is contained in:
@@ -24,6 +24,7 @@ import (
|
|||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
|
||||||
|
domain_device "git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/task"
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/task"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
|
||||||
@@ -60,13 +61,14 @@ func NewAPI(cfg config.ServerConfig,
|
|||||||
userRepo repository.UserRepository,
|
userRepo repository.UserRepository,
|
||||||
deviceRepository repository.DeviceRepository,
|
deviceRepository repository.DeviceRepository,
|
||||||
areaControllerRepository repository.AreaControllerRepository,
|
areaControllerRepository repository.AreaControllerRepository,
|
||||||
deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库
|
deviceTemplateRepository repository.DeviceTemplateRepository,
|
||||||
planRepository repository.PlanRepository,
|
planRepository repository.PlanRepository,
|
||||||
pigFarmService service.PigFarmService,
|
pigFarmService service.PigFarmService,
|
||||||
pigBatchService service.PigBatchService, // 添加猪群服务
|
pigBatchService service.PigBatchService,
|
||||||
userActionLogRepository repository.UserActionLogRepository,
|
userActionLogRepository repository.UserActionLogRepository,
|
||||||
tokenService token.TokenService,
|
tokenService token.TokenService,
|
||||||
auditService audit.Service, // 注入审计服务
|
auditService audit.Service,
|
||||||
|
deviceService domain_device.Service,
|
||||||
listenHandler webhook.ListenHandler,
|
listenHandler webhook.ListenHandler,
|
||||||
analysisTaskManager *task.AnalysisPlanTaskManager) *API {
|
analysisTaskManager *task.AnalysisPlanTaskManager) *API {
|
||||||
// 设置 Gin 模式,例如 gin.ReleaseMode (生产模式) 或 gin.DebugMode (开发模式)
|
// 设置 Gin 模式,例如 gin.ReleaseMode (生产模式) 或 gin.DebugMode (开发模式)
|
||||||
@@ -93,7 +95,7 @@ func NewAPI(cfg config.ServerConfig,
|
|||||||
// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
|
// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
|
||||||
userController: user.NewController(userRepo, userActionLogRepository, logger, tokenService),
|
userController: user.NewController(userRepo, userActionLogRepository, logger, tokenService),
|
||||||
// 在 NewAPI 中初始化设备控制器,并将其作为 API 结构体的成员
|
// 在 NewAPI 中初始化设备控制器,并将其作为 API 结构体的成员
|
||||||
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, logger),
|
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, deviceService, logger),
|
||||||
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
|
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
|
||||||
planController: plan.NewController(logger, planRepository, analysisTaskManager),
|
planController: plan.NewController(logger, planRepository, analysisTaskManager),
|
||||||
// 在 NewAPI 中初始化猪场管理控制器
|
// 在 NewAPI 中初始化猪场管理控制器
|
||||||
@@ -165,6 +167,7 @@ func (a *API) setupRoutes() {
|
|||||||
deviceGroup.GET("/:id", a.deviceController.GetDevice) // 获取单个设备
|
deviceGroup.GET("/:id", a.deviceController.GetDevice) // 获取单个设备
|
||||||
deviceGroup.PUT("/:id", a.deviceController.UpdateDevice) // 更新设备
|
deviceGroup.PUT("/:id", a.deviceController.UpdateDevice) // 更新设备
|
||||||
deviceGroup.DELETE("/:id", a.deviceController.DeleteDevice) // 删除设备
|
deviceGroup.DELETE("/:id", a.deviceController.DeleteDevice) // 删除设备
|
||||||
|
deviceGroup.POST("/manual-control/:id", a.deviceController.ManualControl) // 手动控制设备
|
||||||
}
|
}
|
||||||
a.logger.Info("设备相关接口注册成功 (需要认证和审计)")
|
a.logger.Info("设备相关接口注册成功 (需要认证和审计)")
|
||||||
|
|
||||||
@@ -236,7 +239,7 @@ func (a *API) setupRoutes() {
|
|||||||
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) // 删除猪群
|
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) // 删除猪群
|
||||||
pigBatchGroup.POST("/assign-pens/:id", a.pigBatchController.AssignEmptyPensToBatch) // 为猪群分配空栏
|
pigBatchGroup.POST("/assign-pens/:id", a.pigBatchController.AssignEmptyPensToBatch) // 为猪群分配空栏
|
||||||
pigBatchGroup.POST("/reclassify-pen/:fromBatchID", a.pigBatchController.ReclassifyPenToNewBatch) // 将猪栏划拨到新群
|
pigBatchGroup.POST("/reclassify-pen/:fromBatchID", a.pigBatchController.ReclassifyPenToNewBatch) // 将猪栏划拨到新群
|
||||||
pigBatchGroup.DELETE("/remove-pen/:penID/:batchID", a.pigBatchController.RemoveEmptyPenFromBatch) // 从猪群移除空栏
|
penGroup.DELETE("/remove-pen/:penID/:batchID", a.pigBatchController.RemoveEmptyPenFromBatch) // 从猪群移除空栏
|
||||||
pigBatchGroup.POST("/move-pigs-into-pen/:id", a.pigBatchController.MovePigsIntoPen) // 将猪只从“虚拟库存”移入指定猪栏
|
pigBatchGroup.POST("/move-pigs-into-pen/:id", a.pigBatchController.MovePigsIntoPen) // 将猪只从“虚拟库存”移入指定猪栏
|
||||||
pigBatchGroup.POST("/sell-pigs/:id", a.pigBatchController.SellPigs) // 处理卖猪业务
|
pigBatchGroup.POST("/sell-pigs/:id", a.pigBatchController.SellPigs) // 处理卖猪业务
|
||||||
pigBatchGroup.POST("/buy-pigs/:id", a.pigBatchController.BuyPigs) // 处理买猪业务
|
pigBatchGroup.POST("/buy-pigs/:id", a.pigBatchController.BuyPigs) // 处理买猪业务
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||||
@@ -19,7 +20,8 @@ import (
|
|||||||
type Controller struct {
|
type Controller struct {
|
||||||
deviceRepo repository.DeviceRepository
|
deviceRepo repository.DeviceRepository
|
||||||
areaControllerRepo repository.AreaControllerRepository
|
areaControllerRepo repository.AreaControllerRepository
|
||||||
deviceTemplateRepo repository.DeviceTemplateRepository // 设备模板仓库
|
deviceTemplateRepo repository.DeviceTemplateRepository
|
||||||
|
deviceService device.Service
|
||||||
logger *logs.Logger
|
logger *logs.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,13 +29,15 @@ type Controller struct {
|
|||||||
func NewController(
|
func NewController(
|
||||||
deviceRepo repository.DeviceRepository,
|
deviceRepo repository.DeviceRepository,
|
||||||
areaControllerRepo repository.AreaControllerRepository,
|
areaControllerRepo repository.AreaControllerRepository,
|
||||||
deviceTemplateRepo repository.DeviceTemplateRepository, // 注入设备模板仓库
|
deviceTemplateRepo repository.DeviceTemplateRepository,
|
||||||
|
deviceService device.Service,
|
||||||
logger *logs.Logger,
|
logger *logs.Logger,
|
||||||
) *Controller {
|
) *Controller {
|
||||||
return &Controller{
|
return &Controller{
|
||||||
deviceRepo: deviceRepo,
|
deviceRepo: deviceRepo,
|
||||||
areaControllerRepo: areaControllerRepo,
|
areaControllerRepo: areaControllerRepo,
|
||||||
deviceTemplateRepo: deviceTemplateRepo,
|
deviceTemplateRepo: deviceTemplateRepo,
|
||||||
|
deviceService: deviceService,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,6 +302,67 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) {
|
|||||||
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备删除成功", nil, actionType, "设备删除成功", deviceID)
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备删除成功", nil, actionType, "设备删除成功", deviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ManualControl godoc
|
||||||
|
// @Summary 手动控制设备
|
||||||
|
// @Description 根据设备ID和指定的动作(开启或关闭)来手动控制设备
|
||||||
|
// @Tags 设备管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "设备ID"
|
||||||
|
// @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令"
|
||||||
|
// @Success 200 {object} controller.Response
|
||||||
|
// @Router /api/v1/devices/manual-control/{id} [post]
|
||||||
|
func (c *Controller) ManualControl(ctx *gin.Context) {
|
||||||
|
const actionType = "手动控制设备"
|
||||||
|
deviceID := ctx.Param("id")
|
||||||
|
|
||||||
|
var req dto.ManualControlDeviceRequest
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dev, err := c.deviceRepo.FindByIDString(deviceID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
c.logger.Warnf("%s: 设备不存在, ID: %s", actionType, deviceID)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备未找到", actionType, "设备不存在", deviceID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "无效的设备ID格式") {
|
||||||
|
c.logger.Errorf("%s: 设备ID格式错误: %v, ID: %s", actionType, err, deviceID)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, err.Error(), actionType, "设备ID格式错误", deviceID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Errorf("%s: 数据库查询失败: %v, ID: %s", actionType, err, deviceID)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "手动控制失败: "+err.Error(), actionType, "数据库查询失败", deviceID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.logger.Infof("%s: 接收到指令, 设备ID: %s, 动作: %s", actionType, deviceID, req.Action)
|
||||||
|
if req.Action == nil {
|
||||||
|
err = c.deviceService.Collect(dev.AreaControllerID, []*models.Device{dev})
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Errorf("%s: 获取设备状态失败: %v, 设备ID: %s", actionType, err, deviceID)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备状态失败: "+err.Error(), actionType, "获取设备状态失败", deviceID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
action := device.DeviceActionStart
|
||||||
|
if *req.Action == "off" {
|
||||||
|
action = device.DeviceActionStop
|
||||||
|
}
|
||||||
|
err = c.deviceService.Switch(dev, action)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Errorf("%s: 设备控制失败: %v, 设备ID: %s", actionType, err, deviceID)
|
||||||
|
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "设备控制失败: "+err.Error(), actionType, "设备控制失败", deviceID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "指令已发送", map[string]interface{}{"device_id": deviceID}, actionType, "指令发送成功", gin.H{"device_id": deviceID, "action": req.Action})
|
||||||
|
}
|
||||||
|
|
||||||
// --- Controller Methods: Area Controllers ---
|
// --- Controller Methods: Area Controllers ---
|
||||||
|
|
||||||
// CreateAreaController godoc
|
// CreateAreaController godoc
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ type UpdateDeviceRequest struct {
|
|||||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ManualControlDeviceRequest 定义了手动控制设备时需要传入的参数
|
||||||
|
type ManualControlDeviceRequest struct {
|
||||||
|
// Action 不传表示这是一个传感器, 会触发一次采集
|
||||||
|
Action *string `json:"action" binding:"oneof=on off"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateAreaControllerRequest 定义了创建区域主控时需要传入的参数
|
// CreateAreaControllerRequest 定义了创建区域主控时需要传入的参数
|
||||||
type CreateAreaControllerRequest struct {
|
type CreateAreaControllerRequest struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ func NewApplication(configPath string) (*Application, error) {
|
|||||||
userActionLogRepo,
|
userActionLogRepo,
|
||||||
tokenService,
|
tokenService,
|
||||||
auditService,
|
auditService,
|
||||||
|
generalDeviceService,
|
||||||
listenHandler,
|
listenHandler,
|
||||||
analysisPlanTaskManager,
|
analysisPlanTaskManager,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user