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/webhook"
|
||||
"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/token"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
|
||||
@@ -60,13 +61,14 @@ func NewAPI(cfg config.ServerConfig,
|
||||
userRepo repository.UserRepository,
|
||||
deviceRepository repository.DeviceRepository,
|
||||
areaControllerRepository repository.AreaControllerRepository,
|
||||
deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库
|
||||
deviceTemplateRepository repository.DeviceTemplateRepository,
|
||||
planRepository repository.PlanRepository,
|
||||
pigFarmService service.PigFarmService,
|
||||
pigBatchService service.PigBatchService, // 添加猪群服务
|
||||
pigBatchService service.PigBatchService,
|
||||
userActionLogRepository repository.UserActionLogRepository,
|
||||
tokenService token.TokenService,
|
||||
auditService audit.Service, // 注入审计服务
|
||||
auditService audit.Service,
|
||||
deviceService domain_device.Service,
|
||||
listenHandler webhook.ListenHandler,
|
||||
analysisTaskManager *task.AnalysisPlanTaskManager) *API {
|
||||
// 设置 Gin 模式,例如 gin.ReleaseMode (生产模式) 或 gin.DebugMode (开发模式)
|
||||
@@ -93,7 +95,7 @@ func NewAPI(cfg config.ServerConfig,
|
||||
// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
|
||||
userController: user.NewController(userRepo, userActionLogRepository, logger, tokenService),
|
||||
// 在 NewAPI 中初始化设备控制器,并将其作为 API 结构体的成员
|
||||
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, logger),
|
||||
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, deviceService, logger),
|
||||
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
|
||||
planController: plan.NewController(logger, planRepository, analysisTaskManager),
|
||||
// 在 NewAPI 中初始化猪场管理控制器
|
||||
@@ -165,6 +167,7 @@ func (a *API) setupRoutes() {
|
||||
deviceGroup.GET("/:id", a.deviceController.GetDevice) // 获取单个设备
|
||||
deviceGroup.PUT("/:id", a.deviceController.UpdateDevice) // 更新设备
|
||||
deviceGroup.DELETE("/:id", a.deviceController.DeleteDevice) // 删除设备
|
||||
deviceGroup.POST("/manual-control/:id", a.deviceController.ManualControl) // 手动控制设备
|
||||
}
|
||||
a.logger.Info("设备相关接口注册成功 (需要认证和审计)")
|
||||
|
||||
@@ -236,7 +239,7 @@ func (a *API) setupRoutes() {
|
||||
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch) // 删除猪群
|
||||
pigBatchGroup.POST("/assign-pens/:id", a.pigBatchController.AssignEmptyPensToBatch) // 为猪群分配空栏
|
||||
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("/sell-pigs/:id", a.pigBatchController.SellPigs) // 处理卖猪业务
|
||||
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/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/models"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||
@@ -19,7 +20,8 @@ import (
|
||||
type Controller struct {
|
||||
deviceRepo repository.DeviceRepository
|
||||
areaControllerRepo repository.AreaControllerRepository
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository // 设备模板仓库
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository
|
||||
deviceService device.Service
|
||||
logger *logs.Logger
|
||||
}
|
||||
|
||||
@@ -27,13 +29,15 @@ type Controller struct {
|
||||
func NewController(
|
||||
deviceRepo repository.DeviceRepository,
|
||||
areaControllerRepo repository.AreaControllerRepository,
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository, // 注入设备模板仓库
|
||||
deviceTemplateRepo repository.DeviceTemplateRepository,
|
||||
deviceService device.Service,
|
||||
logger *logs.Logger,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
deviceRepo: deviceRepo,
|
||||
areaControllerRepo: areaControllerRepo,
|
||||
deviceTemplateRepo: deviceTemplateRepo,
|
||||
deviceService: deviceService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -298,6 +302,67 @@ func (c *Controller) DeleteDevice(ctx *gin.Context) {
|
||||
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 ---
|
||||
|
||||
// CreateAreaController godoc
|
||||
|
||||
@@ -20,6 +20,12 @@ type UpdateDeviceRequest struct {
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// ManualControlDeviceRequest 定义了手动控制设备时需要传入的参数
|
||||
type ManualControlDeviceRequest struct {
|
||||
// Action 不传表示这是一个传感器, 会触发一次采集
|
||||
Action *string `json:"action" binding:"oneof=on off"`
|
||||
}
|
||||
|
||||
// CreateAreaControllerRequest 定义了创建区域主控时需要传入的参数
|
||||
type CreateAreaControllerRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
|
||||
@@ -163,6 +163,7 @@ func NewApplication(configPath string) (*Application, error) {
|
||||
userActionLogRepo,
|
||||
tokenService,
|
||||
auditService,
|
||||
generalDeviceService,
|
||||
listenHandler,
|
||||
analysisPlanTaskManager,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user