实现 猪舍相关路由组 和 猪圈相关路由组

This commit is contained in:
2025-10-03 18:27:53 +08:00
parent 5754a1d94c
commit 8cbe313c89
13 changed files with 840 additions and 47 deletions

View File

@@ -17,9 +17,11 @@ import (
_ "git.huangwc.com/pig/pig-farm-controller/docs" // 引入 swag 生成的 docs
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/device"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/management"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/plan"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/user"
"git.huangwc.com/pig/pig-farm-controller/internal/app/middleware"
"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"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/task"
@@ -45,6 +47,7 @@ type API struct {
userController *user.Controller // 用户控制器实例
deviceController *device.Controller // 设备控制器实例
planController *plan.Controller // 计划控制器实例
pigFarmController *management.PigFarmController // 猪场管理控制器实例
listenHandler webhook.ListenHandler // 设备上行事件监听器
analysisTaskManager *task.AnalysisPlanTaskManager // 计划触发器管理器实例
}
@@ -58,6 +61,7 @@ func NewAPI(cfg config.ServerConfig,
areaControllerRepository repository.AreaControllerRepository,
deviceTemplateRepository repository.DeviceTemplateRepository, // 添加设备模板仓库
planRepository repository.PlanRepository,
pigFarmService service.PigFarmService,
userActionLogRepository repository.UserActionLogRepository,
tokenService token.TokenService,
auditService audit.Service, // 注入审计服务
@@ -90,6 +94,8 @@ func NewAPI(cfg config.ServerConfig,
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, logger),
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
planController: plan.NewController(logger, planRepository, analysisTaskManager),
// 在 NewAPI 中初始化猪场管理控制器
pigFarmController: management.NewPigFarmController(logger, pigFarmService),
}
api.setupRoutes() // 设置所有路由
@@ -192,6 +198,29 @@ func (a *API) setupRoutes() {
planGroup.POST("/:id/stop", a.planController.StopPlan)
}
a.logger.Info("计划相关接口注册成功 (需要认证和审计)")
// 猪舍相关路由组
pigHouseGroup := authGroup.Group("/pighouses")
{
pigHouseGroup.POST("", a.pigFarmController.CreatePigHouse)
pigHouseGroup.GET("", a.pigFarmController.ListPigHouses)
pigHouseGroup.GET("/:id", a.pigFarmController.GetPigHouse)
pigHouseGroup.PUT("/:id", a.pigFarmController.UpdatePigHouse)
pigHouseGroup.DELETE("/:id", a.pigFarmController.DeletePigHouse)
}
a.logger.Info("猪舍相关接口注册成功 (需要认证和审计)")
// 猪圈相关路由组
penGroup := authGroup.Group("/pens")
{
penGroup.POST("", a.pigFarmController.CreatePen)
penGroup.GET("", a.pigFarmController.ListPens)
penGroup.GET("/:id", a.pigFarmController.GetPen)
penGroup.PUT("/:id", a.pigFarmController.UpdatePen)
penGroup.DELETE("/:id", a.pigFarmController.DeletePen)
}
a.logger.Info("猪圈相关接口注册成功 (需要认证和审计)")
}
}

View File

@@ -0,0 +1 @@
package management

View File

@@ -0,0 +1 @@
package management

View File

@@ -0,0 +1 @@
package management

View File

@@ -0,0 +1,426 @@
package management
import (
"errors"
"strconv"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// --- 数据传输对象 (DTOs) ---
// PigHouseResponse 定义了猪舍信息的响应结构
type PigHouseResponse struct {
ID uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
// PenResponse 定义了猪栏信息的响应结构
type PenResponse struct {
ID uint `json:"id"`
PenNumber string `json:"pen_number"`
HouseID uint `json:"house_id"`
Capacity int `json:"capacity"`
Status models.PenStatus `json:"status"`
PigBatchID uint `json:"pig_batch_id"`
}
// CreatePigHouseRequest 定义了创建猪舍的请求结构
type CreatePigHouseRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
}
// UpdatePigHouseRequest 定义了更新猪舍的请求结构
type UpdatePigHouseRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
}
// CreatePenRequest 定义了创建猪栏的请求结构
type CreatePenRequest struct {
PenNumber string `json:"pen_number" binding:"required"`
HouseID uint `json:"house_id" binding:"required"`
Capacity int `json:"capacity" binding:"required"`
Status models.PenStatus `json:"status" binding:"required"`
}
// UpdatePenRequest 定义了更新猪栏的请求结构
type UpdatePenRequest struct {
PenNumber string `json:"pen_number" binding:"required"`
HouseID uint `json:"house_id" binding:"required"`
Capacity int `json:"capacity" binding:"required"`
Status models.PenStatus `json:"status" binding:"required"`
}
// --- 控制器定义 ---
// PigFarmController 负责处理猪舍和猪栏相关的API请求
type PigFarmController struct {
logger *logs.Logger
service service.PigFarmService
}
// NewPigFarmController 创建一个新的 PigFarmController 实例
func NewPigFarmController(logger *logs.Logger, service service.PigFarmService) *PigFarmController {
return &PigFarmController{
logger: logger,
service: service,
}
}
// --- 猪舍 (PigHouse) API 实现 ---
// CreatePigHouse godoc
// @Summary 创建猪舍
// @Description 创建一个新的猪舍
// @Tags 猪场管理
// @Accept json
// @Produce json
// @Param body body CreatePigHouseRequest true "猪舍信息"
// @Success 201 {object} controller.Response{data=PigHouseResponse} "创建成功"
// @Router /api/v1/pighouses [post]
func (c *PigFarmController) CreatePigHouse(ctx *gin.Context) {
const action = "创建猪舍"
var req CreatePigHouseRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
house, err := c.service.CreatePigHouse(req.Name, req.Description)
if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪舍失败", action, "业务逻辑失败", req)
return
}
resp := PigHouseResponse{
ID: house.ID,
Name: house.Name,
Description: house.Description,
}
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
}
// GetPigHouse godoc
// @Summary 获取单个猪舍
// @Description 根据ID获取单个猪舍信息
// @Tags 猪场管理
// @Produce json
// @Param id path int true "猪舍ID"
// @Success 200 {object} controller.Response{data=PigHouseResponse} "获取成功"
// @Router /api/v1/pighouses/{id} [get]
func (c *PigFarmController) GetPigHouse(ctx *gin.Context) {
const action = "获取猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
house, err := c.service.GetPigHouseByID(uint(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪舍失败", action, "业务逻辑失败", id)
return
}
resp := PigHouseResponse{
ID: house.ID,
Name: house.Name,
Description: house.Description,
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
}
// ListPigHouses godoc
// @Summary 获取猪舍列表
// @Description 获取所有猪舍的列表
// @Tags 猪场管理
// @Produce json
// @Success 200 {object} controller.Response{data=[]PigHouseResponse} "获取成功"
// @Router /api/v1/pighouses [get]
func (c *PigFarmController) ListPigHouses(ctx *gin.Context) {
const action = "获取猪舍列表"
houses, err := c.service.ListPigHouses()
if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil)
return
}
var resp []PigHouseResponse
for _, house := range houses {
resp = append(resp, PigHouseResponse{
ID: house.ID,
Name: house.Name,
Description: house.Description,
})
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
}
// UpdatePigHouse godoc
// @Summary 更新猪舍
// @Description 更新一个已存在的猪舍信息
// @Tags 猪场管理
// @Accept json
// @Produce json
// @Param id path int true "猪舍ID"
// @Param body body UpdatePigHouseRequest true "猪舍信息"
// @Success 200 {object} controller.Response{data=PigHouseResponse} "更新成功"
// @Router /api/v1/pighouses/{id} [put]
func (c *PigFarmController) UpdatePigHouse(ctx *gin.Context) {
const action = "更新猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
var req UpdatePigHouseRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
house, err := c.service.UpdatePigHouse(uint(id), req.Name, req.Description)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req)
return
}
resp := PigHouseResponse{
ID: house.ID,
Name: house.Name,
Description: house.Description,
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
}
// DeletePigHouse godoc
// @Summary 删除猪舍
// @Description 根据ID删除一个猪舍
// @Tags 猪场管理
// @Produce json
// @Param id path int true "猪舍ID"
// @Success 200 {object} controller.Response "删除成功"
// @Router /api/v1/pighouses/{id} [delete]
func (c *PigFarmController) DeletePigHouse(ctx *gin.Context) {
const action = "删除猪舍"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
if err := c.service.DeletePigHouse(uint(id)); err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪舍不存在", action, "猪舍不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id)
}
// --- 猪栏 (Pen) API 实现 ---
// CreatePen godoc
// @Summary 创建猪栏
// @Description 创建一个新的猪栏
// @Tags 猪场管理
// @Accept json
// @Produce json
// @Param body body CreatePenRequest true "猪栏信息"
// @Success 201 {object} controller.Response{data=PenResponse} "创建成功"
// @Router /api/v1/pens [post]
func (c *PigFarmController) CreatePen(ctx *gin.Context) {
const action = "创建猪栏"
var req CreatePenRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
pen, err := c.service.CreatePen(req.PenNumber, req.HouseID, req.Capacity, req.Status)
if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "创建猪栏失败", action, "业务逻辑失败", req)
return
}
resp := PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
PigBatchID: pen.PigBatchID,
}
controller.SendSuccessWithAudit(ctx, controller.CodeCreated, "创建成功", resp, action, "创建成功", resp)
}
// GetPen godoc
// @Summary 获取单个猪栏
// @Description 根据ID获取单个猪栏信息
// @Tags 猪场管理
// @Produce json
// @Param id path int true "猪栏ID"
// @Success 200 {object} controller.Response{data=PenResponse} "获取成功"
// @Router /api/v1/pens/{id} [get]
func (c *PigFarmController) GetPen(ctx *gin.Context) {
const action = "获取猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
pen, err := c.service.GetPenByID(uint(id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取猪栏失败", action, "业务逻辑失败", id)
return
}
resp := PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
PigBatchID: pen.PigBatchID,
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
}
// ListPens godoc
// @Summary 获取猪栏列表
// @Description 获取所有猪栏的列表
// @Tags 猪场管理
// @Produce json
// @Success 200 {object} controller.Response{data=[]PenResponse} "获取成功"
// @Router /api/v1/pens [get]
func (c *PigFarmController) ListPens(ctx *gin.Context) {
const action = "获取猪栏列表"
pens, err := c.service.ListPens()
if err != nil {
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取列表失败", action, "业务逻辑失败", nil)
return
}
var resp []PenResponse
for _, pen := range pens {
resp = append(resp, PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
PigBatchID: pen.PigBatchID,
})
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", resp, action, "获取成功", resp)
}
// UpdatePen godoc
// @Summary 更新猪栏
// @Description 更新一个已存在的猪栏信息
// @Tags 猪场管理
// @Accept json
// @Produce json
// @Param id path int true "猪栏ID"
// @Param body body UpdatePenRequest true "猪栏信息"
// @Success 200 {object} controller.Response{data=PenResponse} "更新成功"
// @Router /api/v1/pens/{id} [put]
func (c *PigFarmController) UpdatePen(ctx *gin.Context) {
const action = "更新猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
var req UpdatePenRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
pen, err := c.service.UpdatePen(uint(id), req.PenNumber, req.HouseID, req.Capacity, req.Status)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新失败", action, "业务逻辑失败", req)
return
}
resp := PenResponse{
ID: pen.ID,
PenNumber: pen.PenNumber,
HouseID: pen.HouseID,
Capacity: pen.Capacity,
Status: pen.Status,
PigBatchID: pen.PigBatchID,
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", resp, action, "更新成功", resp)
}
// DeletePen godoc
// @Summary 删除猪栏
// @Description 根据ID删除一个猪栏
// @Tags 猪场管理
// @Produce json
// @Param id path int true "猪栏ID"
// @Success 200 {object} controller.Response "删除成功"
// @Router /api/v1/pens/{id} [delete]
func (c *PigFarmController) DeletePen(ctx *gin.Context) {
const action = "删除猪栏"
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的ID格式", action, "ID格式错误", ctx.Param("id"))
return
}
if err := c.service.DeletePen(uint(id)); err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, "猪栏不存在", action, "猪栏不存在", id)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "删除失败", action, "业务逻辑失败", id)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "删除成功", nil, action, "删除成功", id)
}

View File

@@ -0,0 +1,116 @@
package service
import (
"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"
"gorm.io/gorm"
)
// PigFarmService 提供了猪场资产管理的业务逻辑
type PigFarmService interface {
// PigHouse methods
CreatePigHouse(name, description string) (*models.PigHouse, error)
GetPigHouseByID(id uint) (*models.PigHouse, error)
ListPigHouses() ([]models.PigHouse, error)
UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error)
DeletePigHouse(id uint) error
// Pen methods
CreatePen(penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error)
GetPenByID(id uint) (*models.Pen, error)
ListPens() ([]models.Pen, error)
UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error)
DeletePen(id uint) error
}
type pigFarmService struct {
logger *logs.Logger
repo repository.PigFarmRepository
}
// NewPigFarmService 创建一个新的 PigFarmService 实例
func NewPigFarmService(repo repository.PigFarmRepository, logger *logs.Logger) PigFarmService {
return &pigFarmService{
logger: logger,
repo: repo,
}
}
// --- PigHouse Implementation ---
func (s *pigFarmService) CreatePigHouse(name, description string) (*models.PigHouse, error) {
house := &models.PigHouse{
Name: name,
Description: description,
}
err := s.repo.CreatePigHouse(house)
return house, err
}
func (s *pigFarmService) GetPigHouseByID(id uint) (*models.PigHouse, error) {
return s.repo.GetPigHouseByID(id)
}
func (s *pigFarmService) ListPigHouses() ([]models.PigHouse, error) {
return s.repo.ListPigHouses()
}
func (s *pigFarmService) UpdatePigHouse(id uint, name, description string) (*models.PigHouse, error) {
house := &models.PigHouse{
Model: gorm.Model{ID: id},
Name: name,
Description: description,
}
err := s.repo.UpdatePigHouse(house)
if err != nil {
return nil, err
}
// 返回更新后的完整信息
return s.repo.GetPigHouseByID(id)
}
func (s *pigFarmService) DeletePigHouse(id uint) error {
return s.repo.DeletePigHouse(id)
}
// --- Pen Implementation ---
func (s *pigFarmService) CreatePen(penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) {
pen := &models.Pen{
PenNumber: penNumber,
HouseID: houseID,
Capacity: capacity,
Status: status,
}
err := s.repo.CreatePen(pen)
return pen, err
}
func (s *pigFarmService) GetPenByID(id uint) (*models.Pen, error) {
return s.repo.GetPenByID(id)
}
func (s *pigFarmService) ListPens() ([]models.Pen, error) {
return s.repo.ListPens()
}
func (s *pigFarmService) UpdatePen(id uint, penNumber string, houseID uint, capacity int, status models.PenStatus) (*models.Pen, error) {
pen := &models.Pen{
Model: gorm.Model{ID: id},
PenNumber: penNumber,
HouseID: houseID,
Capacity: capacity,
Status: status,
}
err := s.repo.UpdatePen(pen)
if err != nil {
return nil, err
}
// 返回更新后的完整信息
return s.repo.GetPenByID(id)
}
func (s *pigFarmService) DeletePen(id uint) error {
return s.repo.DeletePen(id)
}