重构设备控制器

This commit is contained in:
2025-12-05 14:44:36 +08:00
parent d7ba7747ec
commit 7017ffa128
12 changed files with 811 additions and 642 deletions

View File

@@ -42,30 +42,32 @@ import (
// API 结构体定义了 HTTP 服务器及其依赖 // API 结构体定义了 HTTP 服务器及其依赖
type API struct { type API struct {
echo *echo.Echo // Echo 引擎实例,用于处理 HTTP 请求 echo *echo.Echo // Echo 引擎实例,用于处理 HTTP 请求
Ctx context.Context // API 组件的上下文,包含日志记录器 Ctx context.Context // API 组件的上下文,包含日志记录器
userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作 userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作
tokenGenerator token.Generator // Token 服务接口,用于 JWT token 的生成和解析 tokenGenerator token.Generator // Token 服务接口,用于 JWT token 的生成和解析
auditService service.AuditService // 审计服务,用于记录用户操作 auditService service.AuditService // 审计服务,用于记录用户操作
httpServer *http.Server // 标准库的 HTTP 服务器实例,用于启动和停止服务 httpServer *http.Server // 标准库的 HTTP 服务器实例,用于启动和停止服务
config config.ServerConfig // API 服务器的配置,使用 infra/config 包中的 ServerConfig config config.ServerConfig // API 服务器的配置,使用 infra/config 包中的 ServerConfig
userController *user.Controller // 用户控制器实例 userController *user.Controller // 用户控制器实例
deviceController *device.Controller // 设备控制器实例 deviceController *device.DeviceController // 设备控制器实例
planController *plan.Controller // 计划控制器实例 deviceTemplateController *device.DeviceTemplateController // 设备模板控制器实例
pigFarmController *management.PigFarmController // 猪场管理控制器实例 areaControllerController *device.AreaControllerController // 区域主控控制器实例
pigBatchController *management.PigBatchController // 猪群控制器实例 planController *plan.Controller // 计划控制器实例
monitorController *monitor.Controller // 数据监控控制器实例 pigFarmController *management.PigFarmController // 猪场管理控制器实例
healthController *health.Controller // 健康检查控制器实例 pigBatchController *management.PigBatchController // 猪群控制器实例
alarmController *alarm.ThresholdAlarmController // 阈值告警控制器 monitorController *monitor.Controller // 数据监控控制器实例
nutrientController *feed.NutrientController // 营养控制器实例 healthController *health.Controller // 健康检查控制器实例
pigAgeStageController *feed.PigAgeStageController // 猪龄阶段控制器实例 alarmController *alarm.ThresholdAlarmController // 阈值告警控制器
pigBreedController *feed.PigBreedController // 猪品种控制器实例 nutrientController *feed.NutrientController // 营养控制器实例
pigTypeController *feed.PigTypeController // 猪种类控制器实例 pigAgeStageController *feed.PigAgeStageController // 猪龄阶段控制器实例
rawMaterialController *feed.RawMaterialController // 原料控制器实例 pigBreedController *feed.PigBreedController // 猪品种控制器实例
recipeController *feed.RecipeController // 配方控制器实例 pigTypeController *feed.PigTypeController // 猪种类控制器实例
inventoryController *inventory.InventoryController // 库存控制器实例 rawMaterialController *feed.RawMaterialController // 原料控制器实例
listenHandler listener.ListenHandler // 设备上行事件监听器 recipeController *feed.RecipeController // 配方控制器实例
analysisTaskManager *domain_plan.AnalysisPlanTaskManager // 计划触发器管理器实例 inventoryController *inventory.InventoryController // 库存控制器实例
listenHandler listener.ListenHandler // 设备上行事件监听器
analysisTaskManager *domain_plan.AnalysisPlanTaskManager // 计划触发器管理器实例
} }
// NewAPI 创建并返回一个新的 API 实例 // NewAPI 创建并返回一个新的 API 实例
@@ -77,6 +79,8 @@ func NewAPI(cfg config.ServerConfig,
pigBatchService service.PigBatchService, pigBatchService service.PigBatchService,
monitorService service.MonitorService, monitorService service.MonitorService,
deviceService service.DeviceService, deviceService service.DeviceService,
deviceTemplateService service.DeviceTemplateService,
areaControllerService service.AreaControllerService,
planService service.PlanService, planService service.PlanService,
userService service.UserService, userService service.UserService,
auditService service.AuditService, auditService service.AuditService,
@@ -104,28 +108,30 @@ func NewAPI(cfg config.ServerConfig,
// 初始化 API 结构体 // 初始化 API 结构体
baseCtx := context.Background() baseCtx := context.Background()
api := &API{ api := &API{
echo: e, echo: e,
Ctx: ctx, Ctx: ctx,
userRepo: userRepo, userRepo: userRepo,
tokenGenerator: tokenGenerator, tokenGenerator: tokenGenerator,
auditService: auditService, auditService: auditService,
config: cfg, config: cfg,
listenHandler: listenHandler, listenHandler: listenHandler,
userController: user.NewController(logs.AddCompName(baseCtx, "UserController"), userService), userController: user.NewController(logs.AddCompName(baseCtx, "UserController"), userService),
deviceController: device.NewController(logs.AddCompName(baseCtx, "DeviceController"), deviceService), deviceController: device.NewDeviceController(logs.AddCompName(baseCtx, "DeviceController"), deviceService),
planController: plan.NewController(logs.AddCompName(baseCtx, "PlanController"), planService), deviceTemplateController: device.NewDeviceTemplateController(logs.AddCompName(baseCtx, "DeviceTemplateController"), deviceTemplateService),
pigFarmController: management.NewPigFarmController(logs.AddCompName(baseCtx, "PigFarmController"), pigFarmService), areaControllerController: device.NewAreaControllerController(logs.AddCompName(baseCtx, "AreaControllerController"), areaControllerService),
pigBatchController: management.NewPigBatchController(logs.AddCompName(baseCtx, "PigBatchController"), pigBatchService), planController: plan.NewController(logs.AddCompName(baseCtx, "PlanController"), planService),
monitorController: monitor.NewController(logs.AddCompName(baseCtx, "MonitorController"), monitorService), pigFarmController: management.NewPigFarmController(logs.AddCompName(baseCtx, "PigFarmController"), pigFarmService),
healthController: health.NewController(logs.AddCompName(baseCtx, "HealthController")), pigBatchController: management.NewPigBatchController(logs.AddCompName(baseCtx, "PigBatchController"), pigBatchService),
alarmController: alarm.NewThresholdAlarmController(logs.AddCompName(baseCtx, "ThresholdAlarmController"), alarmService), monitorController: monitor.NewController(logs.AddCompName(baseCtx, "MonitorController"), monitorService),
nutrientController: feed.NewNutrientController(logs.AddCompName(baseCtx, "NutrientController"), nutrientService), healthController: health.NewController(logs.AddCompName(baseCtx, "HealthController")),
pigAgeStageController: feed.NewPigAgeStageController(logs.AddCompName(baseCtx, "PigAgeStageController"), pigAgeStageService), alarmController: alarm.NewThresholdAlarmController(logs.AddCompName(baseCtx, "ThresholdAlarmController"), alarmService),
pigBreedController: feed.NewPigBreedController(logs.AddCompName(baseCtx, "PigBreedController"), pigBreedService), nutrientController: feed.NewNutrientController(logs.AddCompName(baseCtx, "NutrientController"), nutrientService),
pigTypeController: feed.NewPigTypeController(logs.AddCompName(baseCtx, "PigTypeController"), pigTypeService), pigAgeStageController: feed.NewPigAgeStageController(logs.AddCompName(baseCtx, "PigAgeStageController"), pigAgeStageService),
rawMaterialController: feed.NewRawMaterialController(logs.AddCompName(baseCtx, "RawMaterialController"), rawMaterialService), pigBreedController: feed.NewPigBreedController(logs.AddCompName(baseCtx, "PigBreedController"), pigBreedService),
recipeController: feed.NewRecipeController(logs.AddCompName(baseCtx, "RecipeController"), recipeService), pigTypeController: feed.NewPigTypeController(logs.AddCompName(baseCtx, "PigTypeController"), pigTypeService),
inventoryController: inventory.NewInventoryController(logs.AddCompName(baseCtx, "InventoryController"), inventoryService), rawMaterialController: feed.NewRawMaterialController(logs.AddCompName(baseCtx, "RawMaterialController"), rawMaterialService),
recipeController: feed.NewRecipeController(logs.AddCompName(baseCtx, "RecipeController"), recipeService),
inventoryController: inventory.NewInventoryController(logs.AddCompName(baseCtx, "InventoryController"), inventoryService),
} }
api.setupRoutes() // 设置所有路由 api.setupRoutes() // 设置所有路由

View File

@@ -84,22 +84,22 @@ func (a *API) setupRoutes() {
// 区域主控相关路由组 // 区域主控相关路由组
areaControllerGroup := authGroup.Group("/area-controllers") areaControllerGroup := authGroup.Group("/area-controllers")
{ {
areaControllerGroup.POST("", a.deviceController.CreateAreaController) // 创建区域主控 areaControllerGroup.POST("", a.areaControllerController.CreateAreaController) // 创建区域主控
areaControllerGroup.GET("", a.deviceController.ListAreaControllers) // 获取区域主控列表 areaControllerGroup.GET("", a.areaControllerController.ListAreaControllers) // 获取区域主控列表
areaControllerGroup.GET("/:id", a.deviceController.GetAreaController) // 获取单个区域主控 areaControllerGroup.GET("/:id", a.areaControllerController.GetAreaController) // 获取单个区域主控
areaControllerGroup.PUT("/:id", a.deviceController.UpdateAreaController) // 更新区域主控 areaControllerGroup.PUT("/:id", a.areaControllerController.UpdateAreaController) // 更新区域主控
areaControllerGroup.DELETE("/:id", a.deviceController.DeleteAreaController) // 删除区域主控 areaControllerGroup.DELETE("/:id", a.areaControllerController.DeleteAreaController) // 删除区域主控
} }
logger.Debug("区域主控相关接口注册成功 (需要认证和审计)") logger.Debug("区域主控相关接口注册成功 (需要认证和审计)")
// 设备模板相关路由组 // 设备模板相关路由组
deviceTemplateGroup := authGroup.Group("/device-templates") deviceTemplateGroup := authGroup.Group("/device-templates")
{ {
deviceTemplateGroup.POST("", a.deviceController.CreateDeviceTemplate) // 创建设备模板 deviceTemplateGroup.POST("", a.deviceTemplateController.CreateDeviceTemplate) // 创建设备模板
deviceTemplateGroup.GET("", a.deviceController.ListDeviceTemplates) // 获取设备模板列表 deviceTemplateGroup.GET("", a.deviceTemplateController.ListDeviceTemplates) // 获取设备模板列表
deviceTemplateGroup.GET("/:id", a.deviceController.GetDeviceTemplate) // 获取单个设备模板 deviceTemplateGroup.GET("/:id", a.deviceTemplateController.GetDeviceTemplate) // 获取单个设备模板
deviceTemplateGroup.PUT("/:id", a.deviceController.UpdateDeviceTemplate) // 更新设备模板 deviceTemplateGroup.PUT("/:id", a.deviceTemplateController.UpdateDeviceTemplate) // 更新设备模板
deviceTemplateGroup.DELETE("/:id", a.deviceController.DeleteDeviceTemplate) // 删除设备模板 deviceTemplateGroup.DELETE("/:id", a.deviceTemplateController.DeleteDeviceTemplate) // 删除设备模板
} }
logger.Debug("设备模板相关接口注册成功 (需要认证和审计)") logger.Debug("设备模板相关接口注册成功 (需要认证和审计)")

View File

@@ -0,0 +1,200 @@
package device
import (
"context"
"errors"
"strconv"
"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/service"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"github.com/labstack/echo/v4"
"gorm.io/gorm"
)
// AreaControllerController 区域主控控制器
type AreaControllerController struct {
ctx context.Context
areaControllerService service.AreaControllerService
}
// NewAreaControllerController 创建一个新的区域主控控制器实例
func NewAreaControllerController(
ctx context.Context,
areaControllerService service.AreaControllerService,
) *AreaControllerController {
return &AreaControllerController{
ctx: ctx,
areaControllerService: areaControllerService,
}
}
// CreateAreaController godoc
// @Summary 创建新区域主控
// @Description 根据提供的信息创建一个新区域主控
// @Tags 区域主控管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param areaController body dto.CreateAreaControllerRequest true "区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [post]
func (c *AreaControllerController) CreateAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateAreaController")
const actionType = "创建区域主控"
var req dto.CreateAreaControllerRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
resp, err := c.areaControllerService.CreateAreaController(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层创建失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "服务层创建失败", req)
}
logger.Infof("%s: 区域主控创建成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "区域主控创建成功", resp, actionType, "区域主控创建成功", resp)
}
// GetAreaController godoc
// @Summary 获取区域主控信息
// @Description 根据ID获取单个区域主控的详细信息
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [get]
func (c *AreaControllerController) GetAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetAreaController")
const actionType = "获取区域主控"
acID := ctx.Param("id")
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
resp, err := c.areaControllerService.GetAreaController(reqCtx, uint32(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
}
logger.Errorf("%s: 服务层获取失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "服务层获取失败", acID)
}
logger.Infof("%s: 获取区域主控信息成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控信息成功", resp, actionType, "获取区域主控信息成功", resp)
}
// ListAreaControllers godoc
// @Summary 获取所有区域主控列表
// @Description 获取系统中所有区域主控的列表
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Success 200 {object} controller.Response{data=[]dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [get]
func (c *AreaControllerController) ListAreaControllers(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListAreaControllers")
const actionType = "获取区域主控列表"
resp, err := c.areaControllerService.ListAreaControllers(reqCtx)
if err != nil {
logger.Errorf("%s: 服务层获取列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "服务层获取列表失败", nil)
}
logger.Infof("%s: 获取区域主控列表成功, 数量: %d", actionType, len(resp))
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控列表成功", resp, actionType, "获取区域主控列表成功", resp)
}
// UpdateAreaController godoc
// @Summary 更新区域主控信息
// @Description 根据ID更新一个已存在的区域主控信息
// @Tags 区域主控管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "区域主控ID"
// @Param areaController body dto.UpdateAreaControllerRequest true "要更新的区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [put]
func (c *AreaControllerController) UpdateAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateAreaController")
const actionType = "更新区域主控"
acID := ctx.Param("id")
var req dto.UpdateAreaControllerRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
resp, err := c.areaControllerService.UpdateAreaController(reqCtx, uint32(id), &req)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
}
logger.Errorf("%s: 服务层更新失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "服务层更新失败", acID)
}
logger.Infof("%s: 区域主控更新成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控更新成功", resp, actionType, "区域主控更新成功", resp)
}
// DeleteAreaController godoc
// @Summary 删除区域主控
// @Description 根据ID删除一个区域主控软删除
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response
// @Router /api/v1/area-controllers/{id} [delete]
func (c *AreaControllerController) DeleteAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteAreaController")
const actionType = "删除区域主控"
acID := ctx.Param("id")
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
if err := c.areaControllerService.DeleteAreaController(reqCtx, uint32(id)); err != nil {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
case errors.Is(err, service.ErrAreaControllerInUse):
logger.Warnf("%s: 尝试删除正在被使用的主控, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "主控正在被使用", acID)
default:
logger.Errorf("%s: 服务层删除失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "服务层删除失败", acID)
}
}
logger.Infof("%s: 区域主控删除成功, ID: %s", actionType, acID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控删除成功", nil, actionType, "区域主控删除成功", acID)
}

View File

@@ -14,25 +14,23 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// Controller 设备控制器,封装了所有与设备和区域主控相关的业务逻辑 // DeviceController 设备控制器
type Controller struct { type DeviceController struct {
ctx context.Context ctx context.Context
deviceService service.DeviceService deviceService service.DeviceService
} }
// NewController 创建一个新的设备控制器实例 // NewDeviceController 创建一个新的设备控制器实例
func NewController( func NewDeviceController(
ctx context.Context, ctx context.Context,
deviceService service.DeviceService, deviceService service.DeviceService,
) *Controller { ) *DeviceController {
return &Controller{ return &DeviceController{
ctx: ctx, ctx: ctx,
deviceService: deviceService, deviceService: deviceService,
} }
} }
// --- Controller Methods: Devices ---
// CreateDevice godoc // CreateDevice godoc
// @Summary 创建新设备 // @Summary 创建新设备
// @Description 根据提供的信息创建一个新设备 // @Description 根据提供的信息创建一个新设备
@@ -43,7 +41,7 @@ func NewController(
// @Param device body dto.CreateDeviceRequest true "设备信息" // @Param device body dto.CreateDeviceRequest true "设备信息"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices [post] // @Router /api/v1/devices [post]
func (c *Controller) CreateDevice(ctx echo.Context) error { func (c *DeviceController) CreateDevice(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateDevice") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateDevice")
const actionType = "创建设备" const actionType = "创建设备"
@@ -72,7 +70,7 @@ func (c *Controller) CreateDevice(ctx echo.Context) error {
// @Param id path string true "设备ID" // @Param id path string true "设备ID"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices/{id} [get] // @Router /api/v1/devices/{id} [get]
func (c *Controller) GetDevice(ctx echo.Context) error { func (c *DeviceController) GetDevice(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetDevice") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetDevice")
const actionType = "获取设备" const actionType = "获取设备"
@@ -106,7 +104,7 @@ func (c *Controller) GetDevice(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {object} controller.Response{data=[]dto.DeviceResponse} // @Success 200 {object} controller.Response{data=[]dto.DeviceResponse}
// @Router /api/v1/devices [get] // @Router /api/v1/devices [get]
func (c *Controller) ListDevices(ctx echo.Context) error { func (c *DeviceController) ListDevices(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListDevices") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListDevices")
const actionType = "获取设备列表" const actionType = "获取设备列表"
@@ -131,7 +129,7 @@ func (c *Controller) ListDevices(ctx echo.Context) error {
// @Param device body dto.UpdateDeviceRequest true "要更新的设备信息" // @Param device body dto.UpdateDeviceRequest true "要更新的设备信息"
// @Success 200 {object} controller.Response{data=dto.DeviceResponse} // @Success 200 {object} controller.Response{data=dto.DeviceResponse}
// @Router /api/v1/devices/{id} [put] // @Router /api/v1/devices/{id} [put]
func (c *Controller) UpdateDevice(ctx echo.Context) error { func (c *DeviceController) UpdateDevice(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateDevice") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateDevice")
const actionType = "更新设备" const actionType = "更新设备"
@@ -172,7 +170,7 @@ func (c *Controller) UpdateDevice(ctx echo.Context) error {
// @Param id path string true "设备ID" // @Param id path string true "设备ID"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/devices/{id} [delete] // @Router /api/v1/devices/{id} [delete]
func (c *Controller) DeleteDevice(ctx echo.Context) error { func (c *DeviceController) DeleteDevice(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteDevice") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteDevice")
const actionType = "删除设备" const actionType = "删除设备"
@@ -214,7 +212,7 @@ func (c *Controller) DeleteDevice(ctx echo.Context) error {
// @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令" // @Param manualControl body dto.ManualControlDeviceRequest true "手动控制指令"
// @Success 200 {object} controller.Response // @Success 200 {object} controller.Response
// @Router /api/v1/devices/manual-control/{id} [post] // @Router /api/v1/devices/manual-control/{id} [post]
func (c *Controller) ManualControl(ctx echo.Context) error { func (c *DeviceController) ManualControl(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ManualControlDevice") reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ManualControlDevice")
const actionType = "手动控制设备" const actionType = "手动控制设备"
@@ -243,344 +241,3 @@ func (c *Controller) ManualControl(ctx echo.Context) error {
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "指令已发送", nil, actionType, "指令发送成功", nil) return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "指令已发送", nil, actionType, "指令发送成功", nil)
} }
// --- Controller Methods: Area Controllers ---
// CreateAreaController godoc
// @Summary 创建新区域主控
// @Description 根据提供的信息创建一个新区域主控
// @Tags 区域主控管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param areaController body dto.CreateAreaControllerRequest true "区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [post]
func (c *Controller) CreateAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateAreaController")
const actionType = "创建区域主控"
var req dto.CreateAreaControllerRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
resp, err := c.deviceService.CreateAreaController(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层创建失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建区域主控失败: "+err.Error(), actionType, "服务层创建失败", req)
}
logger.Infof("%s: 区域主控创建成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "区域主控创建成功", resp, actionType, "区域主控创建成功", resp)
}
// GetAreaController godoc
// @Summary 获取区域主控信息
// @Description 根据ID获取单个区域主控的详细信息
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [get]
func (c *Controller) GetAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetAreaController")
const actionType = "获取区域主控"
acID := ctx.Param("id")
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
resp, err := c.deviceService.GetAreaController(reqCtx, uint32(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
}
logger.Errorf("%s: 服务层获取失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控信息失败: "+err.Error(), actionType, "服务层获取失败", acID)
}
logger.Infof("%s: 获取区域主控信息成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控信息成功", resp, actionType, "获取区域主控信息成功", resp)
}
// ListAreaControllers godoc
// @Summary 获取所有区域主控列表
// @Description 获取系统中所有区域主控的列表
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Success 200 {object} controller.Response{data=[]dto.AreaControllerResponse}
// @Router /api/v1/area-controllers [get]
func (c *Controller) ListAreaControllers(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListAreaControllers")
const actionType = "获取区域主控列表"
resp, err := c.deviceService.ListAreaControllers(reqCtx)
if err != nil {
logger.Errorf("%s: 服务层获取列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取区域主控列表失败: "+err.Error(), actionType, "服务层获取列表失败", nil)
}
logger.Infof("%s: 获取区域主控列表成功, 数量: %d", actionType, len(resp))
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取区域主控列表成功", resp, actionType, "获取区域主控列表成功", resp)
}
// UpdateAreaController godoc
// @Summary 更新区域主控信息
// @Description 根据ID更新一个已存在的区域主控信息
// @Tags 区域主控管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "区域主控ID"
// @Param areaController body dto.UpdateAreaControllerRequest true "要更新的区域主控信息"
// @Success 200 {object} controller.Response{data=dto.AreaControllerResponse}
// @Router /api/v1/area-controllers/{id} [put]
func (c *Controller) UpdateAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateAreaController")
const actionType = "更新区域主控"
acID := ctx.Param("id")
var req dto.UpdateAreaControllerRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
resp, err := c.deviceService.UpdateAreaController(reqCtx, uint32(id), &req)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
}
logger.Errorf("%s: 服务层更新失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新区域主控失败: "+err.Error(), actionType, "服务层更新失败", acID)
}
logger.Infof("%s: 区域主控更新成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控更新成功", resp, actionType, "区域主控更新成功", resp)
}
// DeleteAreaController godoc
// @Summary 删除区域主控
// @Description 根据ID删除一个区域主控软删除
// @Tags 区域主控管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "区域主控ID"
// @Success 200 {object} controller.Response
// @Router /api/v1/area-controllers/{id} [delete]
func (c *Controller) DeleteAreaController(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteAreaController")
const actionType = "删除区域主控"
acID := ctx.Param("id")
id, err := strconv.ParseUint(acID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+acID, actionType, "无效的ID", acID)
}
if err := c.deviceService.DeleteAreaController(reqCtx, uint32(id)); err != nil {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
logger.Warnf("%s: 区域主控不存在, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "区域主控未找到", actionType, "区域主控不存在", acID)
case errors.Is(err, service.ErrAreaControllerInUse):
logger.Warnf("%s: 尝试删除正在被使用的主控, ID: %s", actionType, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "主控正在被使用", acID)
default:
logger.Errorf("%s: 服务层删除失败: %v, ID: %s", actionType, err, acID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除区域主控失败: "+err.Error(), actionType, "服务层删除失败", acID)
}
}
logger.Infof("%s: 区域主控删除成功, ID: %s", actionType, acID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "区域主控删除成功", nil, actionType, "区域主控删除成功", acID)
}
// --- Controller Methods: Device Templates ---
// CreateDeviceTemplate godoc
// @Summary 创建新设备模板
// @Description 根据提供的信息创建一个新设备模板
// @Tags 设备模板管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param deviceTemplate body dto.CreateDeviceTemplateRequest true "设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [post]
func (c *Controller) CreateDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateDeviceTemplate")
const actionType = "创建设备模板"
var req dto.CreateDeviceTemplateRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
resp, err := c.deviceService.CreateDeviceTemplate(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层创建失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "服务层创建失败", req)
}
logger.Infof("%s: 设备模板创建成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备模板创建成功", resp, actionType, "设备模板创建成功", resp)
}
// GetDeviceTemplate godoc
// @Summary 获取设备模板信息
// @Description 根据设备模板ID获取单个设备模板的详细信息
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [get]
func (c *Controller) GetDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetDeviceTemplate")
const actionType = "获取设备模板"
dtID := ctx.Param("id")
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
resp, err := c.deviceService.GetDeviceTemplate(reqCtx, uint32(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
}
logger.Errorf("%s: 服务层获取失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "服务层获取失败", dtID)
}
logger.Infof("%s: 获取设备模板信息成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板信息成功", resp, actionType, "获取设备模板信息成功", resp)
}
// ListDeviceTemplates godoc
// @Summary 获取设备模板列表
// @Description 获取系统中所有设备模板的列表
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Success 200 {object} controller.Response{data=[]dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [get]
func (c *Controller) ListDeviceTemplates(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListDeviceTemplates")
const actionType = "获取设备模板列表"
resp, err := c.deviceService.ListDeviceTemplates(reqCtx)
if err != nil {
logger.Errorf("%s: 服务层获取列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "服务层获取列表失败", nil)
}
logger.Infof("%s: 获取设备模板列表成功, 数量: %d", actionType, len(resp))
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板列表成功", resp, actionType, "获取设备模板列表成功", resp)
}
// UpdateDeviceTemplate godoc
// @Summary 更新设备模板信息
// @Description 根据设备模板ID更新一个已存在的设备模板信息
// @Tags 设备模板管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "设备模板ID"
// @Param deviceTemplate body dto.UpdateDeviceTemplateRequest true "要更新的设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [put]
func (c *Controller) UpdateDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateDeviceTemplate")
const actionType = "更新设备模板"
dtID := ctx.Param("id")
var req dto.UpdateDeviceTemplateRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
resp, err := c.deviceService.UpdateDeviceTemplate(reqCtx, uint32(id), &req)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
}
logger.Errorf("%s: 服务层更新失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "服务层更新失败", dtID)
}
logger.Infof("%s: 设备模板更新成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板更新成功", resp, actionType, "设备模板更新成功", resp)
}
// DeleteDeviceTemplate godoc
// @Summary 删除设备模板
// @Description 根据设备模板ID删除一个设备模板软删除
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response
// @Router /api/v1/device-templates/{id} [delete]
func (c *Controller) DeleteDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteDeviceTemplate")
const actionType = "删除设备模板"
dtID := ctx.Param("id")
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
if err := c.deviceService.DeleteDeviceTemplate(reqCtx, uint32(id)); err != nil {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
case errors.Is(err, service.ErrDeviceTemplateInUse):
logger.Warnf("%s: 尝试删除正在被使用的模板, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "模板正在被使用", dtID)
default:
logger.Errorf("%s: 服务层删除失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: "+err.Error(), actionType, "服务层删除失败", dtID)
}
}
logger.Infof("%s: 设备模板删除成功, ID: %s", actionType, dtID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板删除成功", nil, actionType, "设备模板删除成功", dtID)
}

View File

@@ -0,0 +1,201 @@
package device
import (
"context"
"errors"
"strconv"
"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/service"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"github.com/labstack/echo/v4"
"gorm.io/gorm"
)
// DeviceTemplateController 设备模板控制器
type DeviceTemplateController struct {
ctx context.Context
deviceTemplateService service.DeviceTemplateService
}
// NewDeviceTemplateController 创建一个新的设备模板控制器实例
func NewDeviceTemplateController(
ctx context.Context,
deviceTemplateService service.DeviceTemplateService,
) *DeviceTemplateController {
return &DeviceTemplateController{
ctx: ctx,
deviceTemplateService: deviceTemplateService,
}
}
// CreateDeviceTemplate godoc
// @Summary 创建新设备模板
// @Description 根据提供的信息创建一个新设备模板
// @Tags 设备模板管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param deviceTemplate body dto.CreateDeviceTemplateRequest true "设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [post]
func (c *DeviceTemplateController) CreateDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "CreateDeviceTemplate")
const actionType = "创建设备模板"
var req dto.CreateDeviceTemplateRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
resp, err := c.deviceTemplateService.CreateDeviceTemplate(reqCtx, &req)
if err != nil {
logger.Errorf("%s: 服务层创建失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建设备模板失败: "+err.Error(), actionType, "服务层创建失败", req)
}
logger.Infof("%s: 设备模板创建成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "设备模板创建成功", resp, actionType, "设备模板创建成功", resp)
}
// GetDeviceTemplate godoc
// @Summary 获取设备模板信息
// @Description 根据设备模板ID获取单个设备模板的详细信息
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [get]
func (c *DeviceTemplateController) GetDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "GetDeviceTemplate")
const actionType = "获取设备模板"
dtID := ctx.Param("id")
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
resp, err := c.deviceTemplateService.GetDeviceTemplate(reqCtx, uint32(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
}
logger.Errorf("%s: 服务层获取失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板信息失败: "+err.Error(), actionType, "服务层获取失败", dtID)
}
logger.Infof("%s: 获取设备模板信息成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板信息成功", resp, actionType, "获取设备模板信息成功", resp)
}
// ListDeviceTemplates godoc
// @Summary 获取设备模板列表
// @Description 获取系统中所有设备模板的列表
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Success 200 {object} controller.Response{data=[]dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates [get]
func (c *DeviceTemplateController) ListDeviceTemplates(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "ListDeviceTemplates")
const actionType = "获取设备模板列表"
resp, err := c.deviceTemplateService.ListDeviceTemplates(reqCtx)
if err != nil {
logger.Errorf("%s: 服务层获取列表失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取设备模板列表失败: "+err.Error(), actionType, "服务层获取列表失败", nil)
}
logger.Infof("%s: 获取设备模板列表成功, 数量: %d", actionType, len(resp))
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取设备模板列表成功", resp, actionType, "获取设备模板列表成功", resp)
}
// UpdateDeviceTemplate godoc
// @Summary 更新设备模板信息
// @Description 根据设备模板ID更新一个已存在的设备模板信息
// @Tags 设备模板管理
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param id path string true "设备模板ID"
// @Param deviceTemplate body dto.UpdateDeviceTemplateRequest true "要更新的设备模板信息"
// @Success 200 {object} controller.Response{data=dto.DeviceTemplateResponse}
// @Router /api/v1/device-templates/{id} [put]
func (c *DeviceTemplateController) UpdateDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "UpdateDeviceTemplate")
const actionType = "更新设备模板"
dtID := ctx.Param("id")
var req dto.UpdateDeviceTemplateRequest
if err := ctx.Bind(&req); err != nil {
logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error(), actionType, "请求体绑定失败", req)
}
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
resp, err := c.deviceTemplateService.UpdateDeviceTemplate(reqCtx, uint32(id), &req)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
}
logger.Errorf("%s: 服务层更新失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新设备模板失败: "+err.Error(), actionType, "服务层更新失败", dtID)
}
logger.Infof("%s: 设备模板更新成功, ID: %d", actionType, resp.ID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板更新成功", resp, actionType, "设备模板更新成功", resp)
}
// DeleteDeviceTemplate godoc
// @Summary 删除设备模板
// @Description 根据设备模板ID删除一个设备模板软删除
// @Tags 设备模板管理
// @Security BearerAuth
// @Produce json
// @Param id path string true "设备模板ID"
// @Success 200 {object} controller.Response
// @Router /api/v1/device-templates/{id} [delete]
func (c *DeviceTemplateController) DeleteDeviceTemplate(ctx echo.Context) error {
reqCtx, logger := logs.Trace(ctx.Request().Context(), c.ctx, "DeleteDeviceTemplate")
const actionType = "删除设备模板"
dtID := ctx.Param("id")
id, err := strconv.ParseUint(dtID, 10, 64)
if err != nil {
logger.Errorf("%s: 无效的ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID: "+dtID, actionType, "无效的ID", dtID)
}
if err := c.deviceTemplateService.DeleteDeviceTemplate(reqCtx, uint32(id)); err != nil {
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
logger.Warnf("%s: 设备模板不存在, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "设备模板未找到", actionType, "设备模板不存在", dtID)
case errors.Is(err, service.ErrDeviceTemplateInUse):
logger.Warnf("%s: 尝试删除正在被使用的模板, ID: %s", actionType, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), actionType, "模板正在被使用", dtID)
default:
logger.Errorf("%s: 服务层删除失败: %v, ID: %s", actionType, err, dtID)
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除设备模板失败: "+err.Error(), actionType, "服务层删除失败", dtID)
}
}
logger.Infof("%s: 设备模板删除成功, ID: %s", actionType, dtID)
return controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "设备模板删除成功", nil, actionType, "设备模板删除成功", dtID)
}

View File

@@ -0,0 +1,140 @@
package service
import (
"context"
"encoding/json"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"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"
)
// AreaControllerService 定义了应用层的区域主控服务接口。
type AreaControllerService interface {
CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error)
GetAreaController(ctx context.Context, id uint32) (*dto.AreaControllerResponse, error)
ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error)
UpdateAreaController(ctx context.Context, id uint32, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error)
DeleteAreaController(ctx context.Context, id uint32) error
}
// areaControllerService 是 AreaControllerService 接口的具体实现。
type areaControllerService struct {
ctx context.Context
areaControllerRepo repository.AreaControllerRepository
thresholdAlarmService ThresholdAlarmService
}
// NewAreaControllerService 创建一个新的 AreaControllerService 实例。
func NewAreaControllerService(
ctx context.Context,
areaControllerRepo repository.AreaControllerRepository,
thresholdAlarmService ThresholdAlarmService,
) AreaControllerService {
return &areaControllerService{
ctx: ctx,
areaControllerRepo: areaControllerRepo,
thresholdAlarmService: thresholdAlarmService,
}
}
func (s *areaControllerService) CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateAreaController")
propertiesJSON, err := json.Marshal(req.Properties)
if err != nil {
return nil, err
}
ac := &models.AreaController{
Name: req.Name,
NetworkID: req.NetworkID,
Location: req.Location,
Properties: propertiesJSON,
}
if err := ac.SelfCheck(); err != nil {
return nil, err
}
if err := s.areaControllerRepo.Create(serviceCtx, ac); err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(ac)
}
func (s *areaControllerService) GetAreaController(ctx context.Context, id uint32) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetAreaController")
ac, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(ac)
}
func (s *areaControllerService) ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListAreaControllers")
acs, err := s.areaControllerRepo.ListAll(serviceCtx)
if err != nil {
return nil, err
}
return dto.NewListAreaControllerResponse(acs)
}
func (s *areaControllerService) UpdateAreaController(ctx context.Context, id uint32, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateAreaController")
existingAC, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
propertiesJSON, err := json.Marshal(req.Properties)
if err != nil {
return nil, err
}
existingAC.Name = req.Name
existingAC.NetworkID = req.NetworkID
existingAC.Location = req.Location
existingAC.Properties = propertiesJSON
if err := existingAC.SelfCheck(); err != nil {
return nil, err
}
if err := s.areaControllerRepo.Update(serviceCtx, existingAC); err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(existingAC)
}
func (s *areaControllerService) DeleteAreaController(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteAreaController")
// 1. 检查是否存在
_, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return err // 如果未找到gorm会返回 ErrRecordNotFound
}
// 2. 检查是否被使用(业务逻辑)
inUse, err := s.areaControllerRepo.IsAreaControllerUsedByTasks(serviceCtx, id, []models.TaskType{models.TaskTypeAreaCollectorThresholdCheck})
if err != nil {
return err // 返回数据库检查错误
}
if inUse {
return ErrAreaControllerInUse // 返回业务错误
}
// TODO 这个应该用事务处理
err = s.thresholdAlarmService.DeleteAreaThresholdAlarmByAreaControllerID(serviceCtx, id)
if err != nil {
return fmt.Errorf("删除区域阈值告警失败: %w", err)
}
// 3. 执行删除
return s.areaControllerRepo.Delete(serviceCtx, id)
}

View File

@@ -24,7 +24,6 @@ var (
ErrDeviceTemplateInUse = errors.New("设备模板正在被一个或多个设备使用,无法删除") ErrDeviceTemplateInUse = errors.New("设备模板正在被一个或多个设备使用,无法删除")
) )
// DeviceService 定义了应用层的设备服务接口,用于协调设备相关的业务逻辑。
// DeviceService 定义了应用层的设备服务接口,用于协调设备相关的业务逻辑。 // DeviceService 定义了应用层的设备服务接口,用于协调设备相关的业务逻辑。
type DeviceService interface { type DeviceService interface {
CreateDevice(ctx context.Context, req *dto.CreateDeviceRequest) (*dto.DeviceResponse, error) CreateDevice(ctx context.Context, req *dto.CreateDeviceRequest) (*dto.DeviceResponse, error)
@@ -33,26 +32,12 @@ type DeviceService interface {
UpdateDevice(ctx context.Context, id uint32, req *dto.UpdateDeviceRequest) (*dto.DeviceResponse, error) UpdateDevice(ctx context.Context, id uint32, req *dto.UpdateDeviceRequest) (*dto.DeviceResponse, error)
DeleteDevice(ctx context.Context, id uint32) error DeleteDevice(ctx context.Context, id uint32) error
ManualControl(ctx context.Context, id uint32, req *dto.ManualControlDeviceRequest) error ManualControl(ctx context.Context, id uint32, req *dto.ManualControlDeviceRequest) error
CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error)
GetAreaController(ctx context.Context, id uint32) (*dto.AreaControllerResponse, error)
ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error)
UpdateAreaController(ctx context.Context, id uint32, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error)
DeleteAreaController(ctx context.Context, id uint32) error
CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
GetDeviceTemplate(ctx context.Context, id uint32) (*dto.DeviceTemplateResponse, error)
ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error)
UpdateDeviceTemplate(ctx context.Context, id uint32, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
DeleteDeviceTemplate(ctx context.Context, id uint32) error
} }
// deviceService 是 DeviceService 接口的具体实现。 // deviceService 是 DeviceService 接口的具体实现。
type deviceService struct { type deviceService struct {
ctx context.Context ctx context.Context
deviceRepo repository.DeviceRepository deviceRepo repository.DeviceRepository
areaControllerRepo repository.AreaControllerRepository
deviceTemplateRepo repository.DeviceTemplateRepository
deviceDomainSvc device.DeviceOperator deviceDomainSvc device.DeviceOperator
thresholdAlarmService ThresholdAlarmService thresholdAlarmService ThresholdAlarmService
} }
@@ -61,16 +46,12 @@ type deviceService struct {
func NewDeviceService( func NewDeviceService(
ctx context.Context, ctx context.Context,
deviceRepo repository.DeviceRepository, deviceRepo repository.DeviceRepository,
areaControllerRepo repository.AreaControllerRepository,
deviceTemplateRepo repository.DeviceTemplateRepository,
deviceDomainSvc device.DeviceOperator, deviceDomainSvc device.DeviceOperator,
thresholdAlarmService ThresholdAlarmService, thresholdAlarmService ThresholdAlarmService,
) DeviceService { ) DeviceService {
return &deviceService{ return &deviceService{
ctx: ctx, ctx: ctx,
deviceRepo: deviceRepo, deviceRepo: deviceRepo,
areaControllerRepo: areaControllerRepo,
deviceTemplateRepo: deviceTemplateRepo,
deviceDomainSvc: deviceDomainSvc, deviceDomainSvc: deviceDomainSvc,
thresholdAlarmService: thresholdAlarmService, thresholdAlarmService: thresholdAlarmService,
} }
@@ -213,213 +194,3 @@ func (s *deviceService) ManualControl(ctx context.Context, id uint32, req *dto.M
return s.deviceDomainSvc.Switch(serviceCtx, dev, action) return s.deviceDomainSvc.Switch(serviceCtx, dev, action)
} }
} }
// --- Area Controllers ---
func (s *deviceService) CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateAreaController")
propertiesJSON, err := json.Marshal(req.Properties)
if err != nil {
return nil, err
}
ac := &models.AreaController{
Name: req.Name,
NetworkID: req.NetworkID,
Location: req.Location,
Properties: propertiesJSON,
}
if err := ac.SelfCheck(); err != nil {
return nil, err
}
if err := s.areaControllerRepo.Create(serviceCtx, ac); err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(ac)
}
func (s *deviceService) GetAreaController(ctx context.Context, id uint32) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetAreaController")
ac, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(ac)
}
func (s *deviceService) ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListAreaControllers")
acs, err := s.areaControllerRepo.ListAll(serviceCtx)
if err != nil {
return nil, err
}
return dto.NewListAreaControllerResponse(acs)
}
func (s *deviceService) UpdateAreaController(ctx context.Context, id uint32, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateAreaController")
existingAC, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
propertiesJSON, err := json.Marshal(req.Properties)
if err != nil {
return nil, err
}
existingAC.Name = req.Name
existingAC.NetworkID = req.NetworkID
existingAC.Location = req.Location
existingAC.Properties = propertiesJSON
if err := existingAC.SelfCheck(); err != nil {
return nil, err
}
if err := s.areaControllerRepo.Update(serviceCtx, existingAC); err != nil {
return nil, err
}
return dto.NewAreaControllerResponse(existingAC)
}
func (s *deviceService) DeleteAreaController(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteAreaController")
// 1. 检查是否存在
_, err := s.areaControllerRepo.FindByID(serviceCtx, id)
if err != nil {
return err // 如果未找到gorm会返回 ErrRecordNotFound
}
// 2. 检查是否被使用(业务逻辑)
inUse, err := s.areaControllerRepo.IsAreaControllerUsedByTasks(serviceCtx, id, []models.TaskType{models.TaskTypeAreaCollectorThresholdCheck})
if err != nil {
return err // 返回数据库检查错误
}
if inUse {
return ErrAreaControllerInUse // 返回业务错误
}
// TODO 这个应该用事务处理
err = s.thresholdAlarmService.DeleteAreaThresholdAlarmByAreaControllerID(serviceCtx, id)
if err != nil {
return fmt.Errorf("删除区域阈值告警失败: %w", err)
}
// 3. 执行删除
return s.areaControllerRepo.Delete(serviceCtx, id)
}
// --- Device Templates ---
func (s *deviceService) CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateDeviceTemplate")
commandsJSON, err := json.Marshal(req.Commands)
if err != nil {
return nil, err
}
valuesJSON, err := json.Marshal(req.Values)
if err != nil {
return nil, err
}
deviceTemplate := &models.DeviceTemplate{
Name: req.Name,
Manufacturer: req.Manufacturer,
Description: req.Description,
Category: req.Category,
Commands: commandsJSON,
Values: valuesJSON,
}
if err := deviceTemplate.SelfCheck(); err != nil {
return nil, err
}
if err := s.deviceTemplateRepo.Create(serviceCtx, deviceTemplate); err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(deviceTemplate)
}
func (s *deviceService) GetDeviceTemplate(ctx context.Context, id uint32) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetDeviceTemplate")
deviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(deviceTemplate)
}
func (s *deviceService) ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListDeviceTemplates")
deviceTemplates, err := s.deviceTemplateRepo.ListAll(serviceCtx)
if err != nil {
return nil, err
}
return dto.NewListDeviceTemplateResponse(deviceTemplates)
}
func (s *deviceService) UpdateDeviceTemplate(ctx context.Context, id uint32, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateDeviceTemplate")
existingDeviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
commandsJSON, err := json.Marshal(req.Commands)
if err != nil {
return nil, err
}
valuesJSON, err := json.Marshal(req.Values)
if err != nil {
return nil, err
}
existingDeviceTemplate.Name = req.Name
existingDeviceTemplate.Manufacturer = req.Manufacturer
existingDeviceTemplate.Description = req.Description
existingDeviceTemplate.Category = req.Category
existingDeviceTemplate.Commands = commandsJSON
existingDeviceTemplate.Values = valuesJSON
if err := existingDeviceTemplate.SelfCheck(); err != nil {
return nil, err
}
if err := s.deviceTemplateRepo.Update(serviceCtx, existingDeviceTemplate); err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(existingDeviceTemplate)
}
func (s *deviceService) DeleteDeviceTemplate(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteDeviceTemplate")
// 1. 检查是否存在
_, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return err
}
// 2. 检查是否被使用(业务逻辑)
inUse, err := s.deviceTemplateRepo.IsInUse(serviceCtx, id)
if err != nil {
return err
}
if inUse {
return ErrDeviceTemplateInUse // 返回业务错误
}
// 3. 执行删除
return s.deviceTemplateRepo.Delete(serviceCtx, id)
}

View File

@@ -0,0 +1,144 @@
package service
import (
"context"
"encoding/json"
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
"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"
)
// DeviceTemplateService 定义了应用层的设备模板服务接口。
type DeviceTemplateService interface {
CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
GetDeviceTemplate(ctx context.Context, id uint32) (*dto.DeviceTemplateResponse, error)
ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error)
UpdateDeviceTemplate(ctx context.Context, id uint32, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
DeleteDeviceTemplate(ctx context.Context, id uint32) error
}
// deviceTemplateService 是 DeviceTemplateService 接口的具体实现。
type deviceTemplateService struct {
ctx context.Context
deviceTemplateRepo repository.DeviceTemplateRepository
}
// NewDeviceTemplateService 创建一个新的 DeviceTemplateService 实例。
func NewDeviceTemplateService(
ctx context.Context,
deviceTemplateRepo repository.DeviceTemplateRepository,
) DeviceTemplateService {
return &deviceTemplateService{
ctx: ctx,
deviceTemplateRepo: deviceTemplateRepo,
}
}
func (s *deviceTemplateService) CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateDeviceTemplate")
commandsJSON, err := json.Marshal(req.Commands)
if err != nil {
return nil, err
}
valuesJSON, err := json.Marshal(req.Values)
if err != nil {
return nil, err
}
deviceTemplate := &models.DeviceTemplate{
Name: req.Name,
Manufacturer: req.Manufacturer,
Description: req.Description,
Category: req.Category,
Commands: commandsJSON,
Values: valuesJSON,
}
if err := deviceTemplate.SelfCheck(); err != nil {
return nil, err
}
if err := s.deviceTemplateRepo.Create(serviceCtx, deviceTemplate); err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(deviceTemplate)
}
func (s *deviceTemplateService) GetDeviceTemplate(ctx context.Context, id uint32) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetDeviceTemplate")
deviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(deviceTemplate)
}
func (s *deviceTemplateService) ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListDeviceTemplates")
deviceTemplates, err := s.deviceTemplateRepo.ListAll(serviceCtx)
if err != nil {
return nil, err
}
return dto.NewListDeviceTemplateResponse(deviceTemplates)
}
func (s *deviceTemplateService) UpdateDeviceTemplate(ctx context.Context, id uint32, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateDeviceTemplate")
existingDeviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return nil, err
}
commandsJSON, err := json.Marshal(req.Commands)
if err != nil {
return nil, err
}
valuesJSON, err := json.Marshal(req.Values)
if err != nil {
return nil, err
}
existingDeviceTemplate.Name = req.Name
existingDeviceTemplate.Manufacturer = req.Manufacturer
existingDeviceTemplate.Description = req.Description
existingDeviceTemplate.Category = req.Category
existingDeviceTemplate.Commands = commandsJSON
existingDeviceTemplate.Values = valuesJSON
if err := existingDeviceTemplate.SelfCheck(); err != nil {
return nil, err
}
if err := s.deviceTemplateRepo.Update(serviceCtx, existingDeviceTemplate); err != nil {
return nil, err
}
return dto.NewDeviceTemplateResponse(existingDeviceTemplate)
}
func (s *deviceTemplateService) DeleteDeviceTemplate(ctx context.Context, id uint32) error {
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteDeviceTemplate")
// 1. 检查是否存在
_, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
if err != nil {
return err
}
// 2. 检查是否被使用(业务逻辑)
inUse, err := s.deviceTemplateRepo.IsInUse(serviceCtx, id)
if err != nil {
return err
}
if inUse {
return ErrDeviceTemplateInUse // 返回业务错误
}
// 3. 执行删除
return s.deviceTemplateRepo.Delete(serviceCtx, id)
}

View File

@@ -59,6 +59,8 @@ func NewApplication(configPath string) (*Application, error) {
appServices.pigBatchService, appServices.pigBatchService,
appServices.monitorService, appServices.monitorService,
appServices.deviceService, appServices.deviceService,
appServices.deviceTemplateService,
appServices.areaControllerService,
appServices.planService, appServices.planService,
appServices.userService, appServices.userService,
appServices.auditService, appServices.auditService,

View File

@@ -285,6 +285,8 @@ type AppServices struct {
pigBatchService service.PigBatchService pigBatchService service.PigBatchService
monitorService service.MonitorService monitorService service.MonitorService
deviceService service.DeviceService deviceService service.DeviceService
deviceTemplateService service.DeviceTemplateService
areaControllerService service.AreaControllerService
planService service.PlanService planService service.PlanService
userService service.UserService userService service.UserService
auditService service.AuditService auditService service.AuditService
@@ -334,11 +336,15 @@ func initAppServices(ctx context.Context, infra *Infrastructure, domainServices
deviceService := service.NewDeviceService( deviceService := service.NewDeviceService(
logs.AddCompName(baseCtx, "DeviceService"), logs.AddCompName(baseCtx, "DeviceService"),
infra.repos.deviceRepo, infra.repos.deviceRepo,
infra.repos.areaControllerRepo,
infra.repos.deviceTemplateRepo,
domainServices.deviceOperator, domainServices.deviceOperator,
thresholdAlarmService, thresholdAlarmService,
) )
deviceTemplateService := service.NewDeviceTemplateService(logs.AddCompName(baseCtx, "DeviceTemplateService"), infra.repos.deviceTemplateRepo)
areaControllerService := service.NewAreaControllerService(
logs.AddCompName(baseCtx, "AreaControllerService"),
infra.repos.areaControllerRepo,
thresholdAlarmService,
)
auditService := service.NewAuditService(logs.AddCompName(baseCtx, "AuditService"), infra.repos.userActionLogRepo) auditService := service.NewAuditService(logs.AddCompName(baseCtx, "AuditService"), infra.repos.userActionLogRepo)
planService := service.NewPlanService(logs.AddCompName(baseCtx, "AppPlanService"), domainServices.planService) planService := service.NewPlanService(logs.AddCompName(baseCtx, "AppPlanService"), domainServices.planService)
@@ -356,6 +362,8 @@ func initAppServices(ctx context.Context, infra *Infrastructure, domainServices
pigBatchService: pigBatchService, pigBatchService: pigBatchService,
monitorService: monitorService, monitorService: monitorService,
deviceService: deviceService, deviceService: deviceService,
deviceTemplateService: deviceTemplateService,
areaControllerService: areaControllerService,
auditService: auditService, auditService: auditService,
planService: planService, planService: planService,
userService: userService, userService: userService,

View File

@@ -1 +1,37 @@
package device package device
import (
"context"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
)
// otaServiceImpl 是 OtaService 接口的实现。
type otaServiceImpl struct {
otaRepo repository.OtaRepository
deviceRepo repository.DeviceRepository
}
// NewOtaService 创建一个新的 OtaService 实例。
func NewOtaService(otaRepo repository.OtaRepository, deviceRepo repository.DeviceRepository) OtaService {
return &otaServiceImpl{
otaRepo: otaRepo,
deviceRepo: deviceRepo,
}
}
func (o *otaServiceImpl) StartUpgrade(ctx context.Context, areaControllerID uint32, firmwarePath, targetVersion string) (uint32, error) {
//TODO implement me
panic("implement me")
}
func (o *otaServiceImpl) GetUpgradeProgress(ctx context.Context, taskID uint32) (status models.OTATaskStatus, err error) {
//TODO implement me
panic("implement me")
}
func (o *otaServiceImpl) StopUpgrade(ctx context.Context, taskID uint32) error {
//TODO implement me
panic("implement me")
}

View File

@@ -50,7 +50,9 @@ internal/app/api/api.go
internal/app/api/router.go internal/app/api/router.go
internal/app/controller/alarm/threshold_alarm_controller.go internal/app/controller/alarm/threshold_alarm_controller.go
internal/app/controller/auth_utils.go internal/app/controller/auth_utils.go
internal/app/controller/device/area_controller_controller.go
internal/app/controller/device/device_controller.go internal/app/controller/device/device_controller.go
internal/app/controller/device/device_template_controller.go
internal/app/controller/feed/nutrient_controller.go internal/app/controller/feed/nutrient_controller.go
internal/app/controller/feed/pig_age_stage_controller.go internal/app/controller/feed/pig_age_stage_controller.go
internal/app/controller/feed/pig_breed_controller.go internal/app/controller/feed/pig_breed_controller.go
@@ -94,8 +96,10 @@ internal/app/listener/lora_listener.go
internal/app/listener/transport.go internal/app/listener/transport.go
internal/app/middleware/audit.go internal/app/middleware/audit.go
internal/app/middleware/auth.go internal/app/middleware/auth.go
internal/app/service/area_controller_service.go
internal/app/service/audit_service.go internal/app/service/audit_service.go
internal/app/service/device_service.go internal/app/service/device_service.go
internal/app/service/device_template_service.go
internal/app/service/inventory_service.go internal/app/service/inventory_service.go
internal/app/service/monitor_service.go internal/app/service/monitor_service.go
internal/app/service/nutrient_service.go internal/app/service/nutrient_service.go