更新猪群对应猪栏接口变更

This commit is contained in:
2025-10-06 23:10:58 +08:00
parent aac0324616
commit 632bd20e7d
8 changed files with 680 additions and 60 deletions

View File

@@ -947,6 +947,83 @@ const docTemplate = `{
}
}
},
"/api/v1/pig-batches/{batchID}/remove-pen/{penID}": {
"delete": {
"description": "将一个空闲猪栏从指定的猪批次中移除",
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "从猪批次移除空栏",
"parameters": [
{
"type": "integer",
"description": "猪批次ID",
"name": "batchID",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "待移除的猪栏ID",
"name": "penID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "移除成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{fromBatchID}/reclassify-pen": {
"post": {
"description": "将一个猪栏(连同其中的猪只)从一个批次整体划拨到另一个批次",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "将猪栏划拨到新批次",
"parameters": [
{
"type": "integer",
"description": "源猪批次ID",
"name": "fromBatchID",
"in": "path",
"required": true
},
{
"description": "划拨请求信息 (包含目标批次ID、猪栏ID和备注)",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ReclassifyPenToNewBatchRequest"
}
}
],
"responses": {
"200": {
"description": "划拨成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{id}": {
"get": {
"description": "根据ID获取单个猪批次信息",
@@ -1066,9 +1143,9 @@ const docTemplate = `{
}
}
},
"/api/v1/pig-batches/{id}/pens": {
"put": {
"description": "更新指定猪批次当前关联的猪栏列表",
"/api/v1/pig-batches/{id}/assign-pens": {
"post": {
"description": "将一个或多个空闲猪栏分配给指定猪批次",
"consumes": [
"application/json"
],
@@ -1078,7 +1155,7 @@ const docTemplate = `{
"tags": [
"猪批次管理"
],
"summary": "更新猪批次关联的猪栏",
"summary": "猪批次分配空栏",
"parameters": [
{
"type": "integer",
@@ -1088,18 +1165,59 @@ const docTemplate = `{
"required": true
},
{
"description": "猪批次关联的猪栏ID列表",
"description": "待分配的猪栏ID列表",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PigBatchUpdatePensRequest"
"$ref": "#/definitions/dto.AssignEmptyPensToBatchRequest"
}
}
],
"responses": {
"200": {
"description": "更新成功",
"description": "分配成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{id}/move-pigs-into-pen": {
"post": {
"description": "将指定数量的猪只从批次的“虚拟库存”移入一个已分配的猪栏",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "将猪只从“虚拟库存”移入指定猪栏",
"parameters": [
{
"type": "integer",
"description": "猪批次ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "移入猪只请求信息 (包含目标猪栏ID、数量和备注)",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.MovePigsIntoPenRequest"
}
}
],
"responses": {
"200": {
"description": "移入成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
@@ -1809,6 +1927,9 @@ const docTemplate = `{
}
}
},
"dto.AssignEmptyPensToBatchRequest": {
"type": "object"
},
"dto.CreateAreaControllerRequest": {
"type": "object",
"required": [
@@ -2144,6 +2265,28 @@ const docTemplate = `{
}
}
},
"dto.MovePigsIntoPenRequest": {
"type": "object",
"required": [
"quantity",
"toPenID"
],
"properties": {
"quantity": {
"description": "移入猪只数量",
"type": "integer",
"minimum": 1
},
"remarks": {
"description": "备注",
"type": "string"
},
"toPenID": {
"description": "目标猪栏ID",
"type": "integer"
}
}
},
"dto.PenResponse": {
"type": "object",
"properties": {
@@ -2298,9 +2441,6 @@ const docTemplate = `{
}
}
},
"dto.PigBatchUpdatePensRequest": {
"type": "object"
},
"dto.PigHouseResponse": {
"type": "object",
"properties": {
@@ -2380,6 +2520,27 @@ const docTemplate = `{
}
}
},
"dto.ReclassifyPenToNewBatchRequest": {
"type": "object",
"required": [
"penID",
"toBatchID"
],
"properties": {
"penID": {
"description": "待划拨的猪栏ID",
"type": "integer"
},
"remarks": {
"description": "备注",
"type": "string"
},
"toBatchID": {
"description": "目标猪批次ID",
"type": "integer"
}
}
},
"dto.SubPlanResponse": {
"type": "object",
"properties": {

View File

@@ -936,6 +936,83 @@
}
}
},
"/api/v1/pig-batches/{batchID}/remove-pen/{penID}": {
"delete": {
"description": "将一个空闲猪栏从指定的猪批次中移除",
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "从猪批次移除空栏",
"parameters": [
{
"type": "integer",
"description": "猪批次ID",
"name": "batchID",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "待移除的猪栏ID",
"name": "penID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "移除成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{fromBatchID}/reclassify-pen": {
"post": {
"description": "将一个猪栏(连同其中的猪只)从一个批次整体划拨到另一个批次",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "将猪栏划拨到新批次",
"parameters": [
{
"type": "integer",
"description": "源猪批次ID",
"name": "fromBatchID",
"in": "path",
"required": true
},
{
"description": "划拨请求信息 (包含目标批次ID、猪栏ID和备注)",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ReclassifyPenToNewBatchRequest"
}
}
],
"responses": {
"200": {
"description": "划拨成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{id}": {
"get": {
"description": "根据ID获取单个猪批次信息",
@@ -1055,9 +1132,9 @@
}
}
},
"/api/v1/pig-batches/{id}/pens": {
"put": {
"description": "更新指定猪批次当前关联的猪栏列表",
"/api/v1/pig-batches/{id}/assign-pens": {
"post": {
"description": "将一个或多个空闲猪栏分配给指定猪批次",
"consumes": [
"application/json"
],
@@ -1067,7 +1144,7 @@
"tags": [
"猪批次管理"
],
"summary": "更新猪批次关联的猪栏",
"summary": "猪批次分配空栏",
"parameters": [
{
"type": "integer",
@@ -1077,18 +1154,59 @@
"required": true
},
{
"description": "猪批次关联的猪栏ID列表",
"description": "待分配的猪栏ID列表",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PigBatchUpdatePensRequest"
"$ref": "#/definitions/dto.AssignEmptyPensToBatchRequest"
}
}
],
"responses": {
"200": {
"description": "更新成功",
"description": "分配成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
}
}
}
},
"/api/v1/pig-batches/{id}/move-pigs-into-pen": {
"post": {
"description": "将指定数量的猪只从批次的“虚拟库存”移入一个已分配的猪栏",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"猪批次管理"
],
"summary": "将猪只从“虚拟库存”移入指定猪栏",
"parameters": [
{
"type": "integer",
"description": "猪批次ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "移入猪只请求信息 (包含目标猪栏ID、数量和备注)",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.MovePigsIntoPenRequest"
}
}
],
"responses": {
"200": {
"description": "移入成功",
"schema": {
"$ref": "#/definitions/controller.Response"
}
@@ -1798,6 +1916,9 @@
}
}
},
"dto.AssignEmptyPensToBatchRequest": {
"type": "object"
},
"dto.CreateAreaControllerRequest": {
"type": "object",
"required": [
@@ -2133,6 +2254,28 @@
}
}
},
"dto.MovePigsIntoPenRequest": {
"type": "object",
"required": [
"quantity",
"toPenID"
],
"properties": {
"quantity": {
"description": "移入猪只数量",
"type": "integer",
"minimum": 1
},
"remarks": {
"description": "备注",
"type": "string"
},
"toPenID": {
"description": "目标猪栏ID",
"type": "integer"
}
}
},
"dto.PenResponse": {
"type": "object",
"properties": {
@@ -2287,9 +2430,6 @@
}
}
},
"dto.PigBatchUpdatePensRequest": {
"type": "object"
},
"dto.PigHouseResponse": {
"type": "object",
"properties": {
@@ -2369,6 +2509,27 @@
}
}
},
"dto.ReclassifyPenToNewBatchRequest": {
"type": "object",
"required": [
"penID",
"toBatchID"
],
"properties": {
"penID": {
"description": "待划拨的猪栏ID",
"type": "integer"
},
"remarks": {
"description": "备注",
"type": "string"
},
"toBatchID": {
"description": "目标猪批次ID",
"type": "integer"
}
}
},
"dto.SubPlanResponse": {
"type": "object",
"properties": {

View File

@@ -69,6 +69,8 @@ definitions:
updated_at:
type: string
type: object
dto.AssignEmptyPensToBatchRequest:
type: object
dto.CreateAreaControllerRequest:
properties:
location:
@@ -298,6 +300,22 @@ definitions:
example: testuser
type: string
type: object
dto.MovePigsIntoPenRequest:
properties:
quantity:
description: 移入猪只数量
minimum: 1
type: integer
remarks:
description: 备注
type: string
toPenID:
description: 目标猪栏ID
type: integer
required:
- quantity
- toPenID
type: object
dto.PenResponse:
properties:
capacity:
@@ -398,8 +416,6 @@ definitions:
- $ref: '#/definitions/models.PigBatchStatus'
description: 批次状态,可选
type: object
dto.PigBatchUpdatePensRequest:
type: object
dto.PigHouseResponse:
properties:
description:
@@ -450,6 +466,21 @@ definitions:
$ref: '#/definitions/dto.TaskResponse'
type: array
type: object
dto.ReclassifyPenToNewBatchRequest:
properties:
penID:
description: 待划拨的猪栏ID
type: integer
remarks:
description: 备注
type: string
toBatchID:
description: 目标猪批次ID
type: integer
required:
- penID
- toBatchID
type: object
dto.SubPlanResponse:
properties:
child_plan:
@@ -1373,6 +1404,57 @@ paths:
summary: 创建猪批次
tags:
- 猪批次管理
/api/v1/pig-batches/{batchID}/remove-pen/{penID}:
delete:
description: 将一个空闲猪栏从指定的猪批次中移除
parameters:
- description: 猪批次ID
in: path
name: batchID
required: true
type: integer
- description: 待移除的猪栏ID
in: path
name: penID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: 移除成功
schema:
$ref: '#/definitions/controller.Response'
summary: 从猪批次移除空栏
tags:
- 猪批次管理
/api/v1/pig-batches/{fromBatchID}/reclassify-pen:
post:
consumes:
- application/json
description: 将一个猪栏(连同其中的猪只)从一个批次整体划拨到另一个批次
parameters:
- description: 源猪批次ID
in: path
name: fromBatchID
required: true
type: integer
- description: 划拨请求信息 (包含目标批次ID、猪栏ID和备注)
in: body
name: body
required: true
schema:
$ref: '#/definitions/dto.ReclassifyPenToNewBatchRequest'
produces:
- application/json
responses:
"200":
description: 划拨成功
schema:
$ref: '#/definitions/controller.Response'
summary: 将猪栏划拨到新批次
tags:
- 猪批次管理
/api/v1/pig-batches/{id}:
delete:
description: 根据ID删除一个猪批次
@@ -1446,31 +1528,58 @@ paths:
summary: 更新猪批次
tags:
- 猪批次管理
/api/v1/pig-batches/{id}/pens:
put:
/api/v1/pig-batches/{id}/assign-pens:
post:
consumes:
- application/json
description: 更新指定猪批次当前关联的猪栏列表
description: 将一个或多个空闲猪栏分配给指定猪批次
parameters:
- description: 猪批次ID
in: path
name: id
required: true
type: integer
- description: 猪批次关联的猪栏ID列表
- description: 待分配的猪栏ID列表
in: body
name: body
required: true
schema:
$ref: '#/definitions/dto.PigBatchUpdatePensRequest'
$ref: '#/definitions/dto.AssignEmptyPensToBatchRequest'
produces:
- application/json
responses:
"200":
description: 更新成功
description: 分配成功
schema:
$ref: '#/definitions/controller.Response'
summary: 更新猪批次关联的猪
summary: 猪批次分配空
tags:
- 猪批次管理
/api/v1/pig-batches/{id}/move-pigs-into-pen:
post:
consumes:
- application/json
description: 将指定数量的猪只从批次的“虚拟库存”移入一个已分配的猪栏
parameters:
- description: 猪批次ID
in: path
name: id
required: true
type: integer
- description: 移入猪只请求信息 (包含目标猪栏ID、数量和备注)
in: body
name: body
required: true
schema:
$ref: '#/definitions/dto.MovePigsIntoPenRequest'
produces:
- application/json
responses:
"200":
description: 移入成功
schema:
$ref: '#/definitions/controller.Response'
summary: 将猪只从“虚拟库存”移入指定猪栏
tags:
- 猪批次管理
/api/v1/pig-houses:

View File

@@ -234,7 +234,10 @@ func (a *API) setupRoutes() {
pigBatchGroup.GET("/:id", a.pigBatchController.GetPigBatch)
pigBatchGroup.PUT("/:id", a.pigBatchController.UpdatePigBatch)
pigBatchGroup.DELETE("/:id", a.pigBatchController.DeletePigBatch)
pigBatchGroup.PUT("/:id/pens", a.pigBatchController.UpdatePigBatchPens)
pigBatchGroup.POST("/:id/assign-pens", a.pigBatchController.AssignEmptyPensToBatch)
pigBatchGroup.POST("/:fromBatchID/reclassify-pen", a.pigBatchController.ReclassifyPenToNewBatch)
pigBatchGroup.DELETE("/:batchID/remove-pen/:penID", a.pigBatchController.RemoveEmptyPenFromBatch)
pigBatchGroup.POST("/:id/move-pigs-into-pen", a.pigBatchController.MovePigsIntoPen)
}
a.logger.Info("猪批次相关接口注册成功 (需要认证和审计)")

View File

@@ -179,43 +179,171 @@ func (c *PigBatchController) ListPigBatches(ctx *gin.Context) {
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取成功", respDTOs, action, "获取成功", respDTOs)
}
// UpdatePigBatchPens godoc
// @Summary 更新猪批次关联的猪
// @Description 更新指定猪批次当前关联的猪栏列表
// AssignEmptyPensToBatch godoc
// @Summary 猪批次分配空
// @Description 将一个或多个空闲猪栏分配给指定猪批次
// @Tags 猪批次管理
// @Accept json
// @Produce json
// @Param id path int true "猪批次ID"
// @Param body body dto.PigBatchUpdatePensRequest true "猪批次关联的猪栏ID列表"
// @Success 200 {object} controller.Response "更新成功"
// @Router /api/v1/pig-batches/{id}/pens [put]
func (c *PigBatchController) UpdatePigBatchPens(ctx *gin.Context) {
const action = "更新猪批次关联猪栏"
// @Param body body dto.AssignEmptyPensToBatchRequest true "待分配的猪栏ID列表"
// @Success 200 {object} controller.Response "分配成功"
// @Router /api/v1/pig-batches/{id}/assign-pens [post]
func (c *PigBatchController) AssignEmptyPensToBatch(ctx *gin.Context) {
const action = "猪批次分配空栏"
batchID, 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 dto.PigBatchUpdatePensRequest
var req dto.AssignEmptyPensToBatchRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
err = c.service.UpdatePigBatchPens(uint(batchID), req.PenIDs)
userID, err := controller.GetOperatorIDFromContext(ctx)
err = c.service.AssignEmptyPensToBatch(uint(batchID), req.PenIDs, userID)
if err != nil {
if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), batchID)
return
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenStatusInvalidForAllocation) || errors.Is(err, service.ErrPenNotAssociatedWithBatch) {
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenStatusInvalidForAllocation) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), batchID)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "更新猪批次关联猪栏失败", action, err.Error(), batchID)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "分配空栏失败", action, err.Error(), batchID)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "更新成功", nil, action, "更新成功", batchID)
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "分配成功", nil, action, "分配成功", batchID)
}
// ReclassifyPenToNewBatch godoc
// @Summary 将猪栏划拨到新批次
// @Description 将一个猪栏(连同其中的猪只)从一个批次整体划拨到另一个批次
// @Tags 猪批次管理
// @Accept json
// @Produce json
// @Param fromBatchID path int true "源猪批次ID"
// @Param body body dto.ReclassifyPenToNewBatchRequest true "划拨请求信息 (包含目标批次ID、猪栏ID和备注)"
// @Success 200 {object} controller.Response "划拨成功"
// @Router /api/v1/pig-batches/{fromBatchID}/reclassify-pen [post]
func (c *PigBatchController) ReclassifyPenToNewBatch(ctx *gin.Context) {
const action = "划拨猪栏到新批次"
fromBatchID, err := strconv.ParseUint(ctx.Param("fromBatchID"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的源猪批次ID格式", action, "ID格式错误", ctx.Param("fromBatchID"))
return
}
var req dto.ReclassifyPenToNewBatchRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
userID, err := controller.GetOperatorIDFromContext(ctx)
err = c.service.ReclassifyPenToNewBatch(uint(fromBatchID), req.ToBatchID, req.PenID, userID, req.Remarks)
if err != nil {
if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), fromBatchID)
return
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenOccupiedByOtherBatch) || errors.Is(err, service.ErrPenNotAssociatedWithBatch) || errors.Is(err, service.ErrInvalidOperation) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), fromBatchID)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "划拨猪栏失败", action, err.Error(), fromBatchID)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "划拨成功", nil, action, "划拨成功", fromBatchID)
}
// RemoveEmptyPenFromBatch godoc
// @Summary 从猪批次移除空栏
// @Description 将一个空闲猪栏从指定的猪批次中移除
// @Tags 猪批次管理
// @Produce json
// @Param batchID path int true "猪批次ID"
// @Param penID path int true "待移除的猪栏ID"
// @Success 200 {object} controller.Response "移除成功"
// @Router /api/v1/pig-batches/{batchID}/remove-pen/{penID} [delete]
func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx *gin.Context) {
const action = "从猪批次移除空栏"
batchID, err := strconv.ParseUint(ctx.Param("batchID"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪批次ID格式", action, "ID格式错误", ctx.Param("batchID"))
return
}
penID, err := strconv.ParseUint(ctx.Param("penID"), 10, 32)
if err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的猪栏ID格式", action, "ID格式错误", ctx.Param("penID"))
return
}
err = c.service.RemoveEmptyPenFromBatch(uint(batchID), uint(penID))
if err != nil {
if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) || errors.Is(err, service.ErrPenNotAssociatedWithBatch) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), batchID)
return
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrPenNotEmpty) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), batchID)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "移除空栏失败", action, err.Error(), batchID)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "移除成功", nil, action, "移除成功", batchID)
}
// MovePigsIntoPen godoc
// @Summary 将猪只从“虚拟库存”移入指定猪栏
// @Description 将指定数量的猪只从批次的“虚拟库存”移入一个已分配的猪栏
// @Tags 猪批次管理
// @Accept json
// @Produce json
// @Param id path int true "猪批次ID"
// @Param body body dto.MovePigsIntoPenRequest true "移入猪只请求信息 (包含目标猪栏ID、数量和备注)"
// @Success 200 {object} controller.Response "移入成功"
// @Router /api/v1/pig-batches/{id}/move-pigs-into-pen [post]
func (c *PigBatchController) MovePigsIntoPen(ctx *gin.Context) {
const action = "将猪只移入猪栏"
batchID, 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 dto.MovePigsIntoPenRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的请求体", action, "请求体绑定失败", req)
return
}
userID, err := controller.GetOperatorIDFromContext(ctx)
err = c.service.MovePigsIntoPen(uint(batchID), req.ToPenID, req.Quantity, userID, req.Remarks)
if err != nil {
if errors.Is(err, service.ErrPigBatchNotFound) || errors.Is(err, service.ErrPenNotFound) {
controller.SendErrorWithAudit(ctx, controller.CodeNotFound, err.Error(), action, err.Error(), batchID)
return
} else if errors.Is(err, service.ErrPigBatchNotActive) || errors.Is(err, service.ErrInvalidOperation) {
controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), batchID)
return
}
c.logger.Errorf("%s: 业务逻辑失败: %v", action, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "移入猪只失败", action, err.Error(), batchID)
return
}
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "移入成功", nil, action, "移入成功", batchID)
}

View File

@@ -44,7 +44,26 @@ type PigBatchResponseDTO struct {
UpdateTime time.Time `json:"update_time"` // 更新时间
}
// PigBatchUpdatePensRequest 用于更新猪批次关联猪栏的请求体
type PigBatchUpdatePensRequest struct {
PenIDs []uint `json:"penIDs" binding:"required,min=0" example:"[1,2,3]"`
// AssignEmptyPensToBatchRequest 用于猪批次分配空栏的请求体
type AssignEmptyPensToBatchRequest struct {
PenIDs []uint `json:"penIDs" binding:"required,min=1" example:"[1,2,3]"` // 待分配的猪栏ID列表
}
// ReclassifyPenToNewBatchRequest 用于将猪栏划拨到新批次的请求体
type ReclassifyPenToNewBatchRequest struct {
ToBatchID uint `json:"toBatchID" binding:"required"` // 目标猪批次ID
PenID uint `json:"penID" binding:"required"` // 待划拨的猪栏ID
Remarks string `json:"remarks"` // 备注
}
// RemoveEmptyPenFromBatchRequest 用于从猪批次移除空栏的请求体
type RemoveEmptyPenFromBatchRequest struct {
PenID uint `json:"penID" binding:"required"` // 待移除的猪栏ID
}
// MovePigsIntoPenRequest 用于将猪只从“虚拟库存”移入指定猪栏的请求体
type MovePigsIntoPenRequest struct {
ToPenID uint `json:"toPenID" binding:"required"` // 目标猪栏ID
Quantity int `json:"quantity" binding:"required,min=1"` // 移入猪只数量
Remarks string `json:"remarks"` // 备注
}

View File

@@ -14,7 +14,10 @@ type PigBatchService interface {
UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error)
DeletePigBatch(id uint) error
ListPigBatches(isActive *bool) ([]*dto.PigBatchResponseDTO, error)
UpdatePigBatchPens(batchID uint, desiredPenIDs []uint) error
AssignEmptyPensToBatch(batchID uint, penIDs []uint, operatorID uint) error
ReclassifyPenToNewBatch(fromBatchID uint, toBatchID uint, penID uint, operatorID uint, remarks string) error
RemoveEmptyPenFromBatch(batchID uint, penID uint) error
MovePigsIntoPen(batchID uint, toPenID uint, quantity int, operatorID uint, remarks string) error
}
// pigBatchService 的实现现在依赖于领域服务接口。
@@ -65,7 +68,7 @@ func (s *pigBatchService) CreatePigBatch(operatorID uint, dto *dto.PigBatchCreat
createdBatch, err := s.domainService.CreatePigBatch(operatorID, batch)
if err != nil {
s.logger.Errorf("应用层: 创建猪批次失败: %v", err)
return nil, mapDomainError(err)
return nil, MapDomainError(err)
}
// 3. 领域模型 -> DTO
@@ -77,7 +80,7 @@ func (s *pigBatchService) GetPigBatch(id uint) (*dto.PigBatchResponseDTO, error)
batch, err := s.domainService.GetPigBatch(id)
if err != nil {
s.logger.Warnf("应用层: 获取猪批次失败, ID: %d, 错误: %v", id, err)
return nil, mapDomainError(err)
return nil, MapDomainError(err)
}
return s.toPigBatchResponseDTO(batch), nil
@@ -89,7 +92,7 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*
existingBatch, err := s.domainService.GetPigBatch(id)
if err != nil {
s.logger.Warnf("应用层: 更新猪批次失败,获取原批次信息错误, ID: %d, 错误: %v", id, err)
return nil, mapDomainError(err)
return nil, MapDomainError(err)
}
// 2. 将DTO中的变更应用到模型上
@@ -116,7 +119,7 @@ func (s *pigBatchService) UpdatePigBatch(id uint, dto *dto.PigBatchUpdateDTO) (*
updatedBatch, err := s.domainService.UpdatePigBatch(existingBatch)
if err != nil {
s.logger.Errorf("应用层: 更新猪批次失败, ID: %d, 错误: %v", id, err)
return nil, mapDomainError(err)
return nil, MapDomainError(err)
}
// 4. 转换并返回结果
@@ -128,7 +131,7 @@ func (s *pigBatchService) DeletePigBatch(id uint) error {
err := s.domainService.DeletePigBatch(id)
if err != nil {
s.logger.Errorf("应用层: 删除猪批次失败, ID: %d, 错误: %v", id, err)
return mapDomainError(err)
return MapDomainError(err)
}
return nil
}
@@ -138,7 +141,7 @@ func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchRespons
batches, err := s.domainService.ListPigBatches(isActive)
if err != nil {
s.logger.Errorf("应用层: 批量查询猪批次失败: %v", err)
return nil, mapDomainError(err)
return nil, MapDomainError(err)
}
var responseDTOs []*dto.PigBatchResponseDTO
@@ -149,12 +152,42 @@ func (s *pigBatchService) ListPigBatches(isActive *bool) ([]*dto.PigBatchRespons
return responseDTOs, nil
}
// UpdatePigBatchPens 将关联猪栏的复杂操作委托给领域服务,并处理错误转换。
func (s *pigBatchService) UpdatePigBatchPens(batchID uint, desiredPenIDs []uint) error {
err := s.domainService.UpdatePigBatchPens(batchID, desiredPenIDs)
// AssignEmptyPensToBatch 委托给领域服务
func (s *pigBatchService) AssignEmptyPensToBatch(batchID uint, penIDs []uint, operatorID uint) error {
err := s.domainService.AssignEmptyPensToBatch(batchID, penIDs, operatorID)
if err != nil {
s.logger.Errorf("应用层: 更新猪批次猪栏关联失败, 批次ID: %d, 错误: %v", batchID, err)
return mapDomainError(err)
s.logger.Errorf("应用层: 猪批次分配空栏失败, 批次ID: %d, 错误: %v", batchID, err)
return MapDomainError(err)
}
return nil
}
// ReclassifyPenToNewBatch 委托给领域服务
func (s *pigBatchService) ReclassifyPenToNewBatch(fromBatchID uint, toBatchID uint, penID uint, operatorID uint, remarks string) error {
err := s.domainService.ReclassifyPenToNewBatch(fromBatchID, toBatchID, penID, operatorID, remarks)
if err != nil {
s.logger.Errorf("应用层: 划拨猪栏到新批次失败, 源批次ID: %d, 错误: %v", fromBatchID, err)
return MapDomainError(err)
}
return nil
}
// RemoveEmptyPenFromBatch 委托给领域服务
func (s *pigBatchService) RemoveEmptyPenFromBatch(batchID uint, penID uint) error {
err := s.domainService.RemoveEmptyPenFromBatch(batchID, penID)
if err != nil {
s.logger.Errorf("应用层: 从猪批次移除空栏失败, 批次ID: %d, 猪栏ID: %d, 错误: %v", batchID, penID, err)
return MapDomainError(err)
}
return nil
}
// MovePigsIntoPen 委托给领域服务
func (s *pigBatchService) MovePigsIntoPen(batchID uint, toPenID uint, quantity int, operatorID uint, remarks string) error {
err := s.domainService.MovePigsIntoPen(batchID, toPenID, quantity, operatorID, remarks)
if err != nil {
s.logger.Errorf("应用层: 将猪只移入猪栏失败, 批次ID: %d, 目标猪栏ID: %d, 错误: %v", batchID, toPenID, err)
return MapDomainError(err)
}
return nil
}

View File

@@ -19,10 +19,12 @@ var (
ErrPenOccupiedByOtherBatch = errors.New("猪栏已被其他批次使用")
ErrPenStatusInvalidForAllocation = errors.New("猪栏状态不允许分配")
ErrPenNotAssociatedWithBatch = errors.New("猪栏未与该批次关联")
ErrPenNotEmpty = errors.New("猪栏内仍有猪只")
ErrInvalidOperation = errors.New("非法操作")
)
// mapDomainError 将领域层的错误转换为应用服务层的公共错误。
func mapDomainError(err error) error {
// MapDomainError 将领域层的错误转换为应用服务层的公共错误。
func MapDomainError(err error) error {
if err == nil {
return nil
}
@@ -42,6 +44,10 @@ func mapDomainError(err error) error {
return ErrPenNotAssociatedWithBatch
case errors.Is(err, domain_pig.ErrPenNotFound):
return ErrPenNotFound
case errors.Is(err, domain_pig.ErrPenNotEmpty):
return ErrPenNotEmpty
case errors.Is(err, domain_pig.ErrInvalidOperation):
return ErrInvalidOperation
// 可以添加更多领域错误到应用层错误的映射
default:
return err // 对于未知的领域错误,直接返回