issue_56 #58
@@ -1,19 +1,21 @@
|
|||||||
package management
|
package management
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
"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"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// mapAndSendError 统一映射服务层错误并发送响应。
|
// mapAndSendError 统一映射服务层错误并发送响应。
|
||||||
// 这个函数将服务层返回的错误转换为控制器层应返回的HTTP状态码和审计信息。
|
// 这个函数将服务层返回的错误转换为控制器层应返回的HTTP状态码和审计信息。
|
||||||
func mapAndSendError(c *PigBatchController, ctx echo.Context, action string, err error, id uint) error {
|
func mapAndSendError(reqContext context.Context, c *PigBatchController, ctx echo.Context, action string, err error, id uint) error {
|
||||||
if errors.Is(err, service.ErrPigBatchNotFound) ||
|
if errors.Is(err, service.ErrPigBatchNotFound) ||
|
||||||
errors.Is(err, service.ErrPenNotFound) ||
|
errors.Is(err, service.ErrPenNotFound) ||
|
||||||
errors.Is(err, service.ErrPenNotAssociatedWithBatch) {
|
errors.Is(err, service.ErrPenNotAssociatedWithBatch) {
|
||||||
@@ -26,7 +28,7 @@ func mapAndSendError(c *PigBatchController, ctx echo.Context, action string, err
|
|||||||
errors.Is(err, service.ErrPenNotEmpty) {
|
errors.Is(err, service.ErrPenNotEmpty) {
|
||||||
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
|
return controller.SendErrorWithAudit(ctx, controller.CodeConflict, err.Error(), action, err.Error(), id)
|
||||||
} else {
|
} else {
|
||||||
c.logger.Errorf("操作[%s]业务逻辑失败: %v", action, err)
|
logs.GetLogger(reqContext).Errorf("操作[%s]业务逻辑失败: %v", action, err)
|
||||||
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, fmt.Sprintf("操作失败: %v", err), action, err.Error(), id)
|
return controller.SendErrorWithAudit(ctx, controller.CodeInternalError, fmt.Sprintf("操作失败: %v", err), action, err.Error(), id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +88,7 @@ func extractOperatorAndPrimaryID(
|
|||||||
// handleAPIRequest 封装了控制器中处理带有请求体和路径参数的API请求的通用逻辑。
|
// handleAPIRequest 封装了控制器中处理带有请求体和路径参数的API请求的通用逻辑。
|
||||||
// 它负责请求体绑定、操作员ID获取、服务层调用、错误映射和响应发送。
|
// 它负责请求体绑定、操作员ID获取、服务层调用、错误映射和响应发送。
|
||||||
func handleAPIRequest[Req any](
|
func handleAPIRequest[Req any](
|
||||||
|
reqContext context.Context,
|
||||||
c *PigBatchController,
|
c *PigBatchController,
|
||||||
ctx echo.Context,
|
ctx echo.Context,
|
||||||
action string,
|
action string,
|
||||||
@@ -108,7 +111,7 @@ func handleAPIRequest[Req any](
|
|||||||
// 3. 执行服务层逻辑
|
// 3. 执行服务层逻辑
|
||||||
err = serviceExecutor(ctx, operatorID, primaryID, reqDTO)
|
err = serviceExecutor(ctx, operatorID, primaryID, reqDTO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mapAndSendError(c, ctx, action, err, primaryID)
|
return mapAndSendError(reqContext, c, ctx, action, err, primaryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 发送成功响应
|
// 4. 发送成功响应
|
||||||
@@ -117,6 +120,7 @@ func handleAPIRequest[Req any](
|
|||||||
|
|
||||||
// handleNoBodyAPIRequest 封装了处理不带请求体,但有路径参数和操作员ID的API请求的通用逻辑。
|
// handleNoBodyAPIRequest 封装了处理不带请求体,但有路径参数和操作员ID的API请求的通用逻辑。
|
||||||
func handleNoBodyAPIRequest(
|
func handleNoBodyAPIRequest(
|
||||||
|
reqContext context.Context,
|
||||||
c *PigBatchController,
|
c *PigBatchController,
|
||||||
ctx echo.Context,
|
ctx echo.Context,
|
||||||
action string,
|
action string,
|
||||||
@@ -133,7 +137,7 @@ func handleNoBodyAPIRequest(
|
|||||||
// 2. 执行服务层逻辑
|
// 2. 执行服务层逻辑
|
||||||
err = serviceExecutor(ctx, operatorID, primaryID)
|
err = serviceExecutor(ctx, operatorID, primaryID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mapAndSendError(c, ctx, action, err, primaryID)
|
return mapAndSendError(reqContext, c, ctx, action, err, primaryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 发送成功响应
|
// 3. 发送成功响应
|
||||||
@@ -142,6 +146,7 @@ func handleNoBodyAPIRequest(
|
|||||||
|
|
||||||
// handleAPIRequestWithResponse 封装了控制器中处理带有请求体、路径参数并返回响应DTO的API请求的通用逻辑。
|
// handleAPIRequestWithResponse 封装了控制器中处理带有请求体、路径参数并返回响应DTO的API请求的通用逻辑。
|
||||||
func handleAPIRequestWithResponse[Req any, Resp any](
|
func handleAPIRequestWithResponse[Req any, Resp any](
|
||||||
|
reqContext context.Context,
|
||||||
c *PigBatchController,
|
c *PigBatchController,
|
||||||
ctx echo.Context,
|
ctx echo.Context,
|
||||||
action string,
|
action string,
|
||||||
@@ -164,7 +169,7 @@ func handleAPIRequestWithResponse[Req any, Resp any](
|
|||||||
// 3. 执行服务层逻辑
|
// 3. 执行服务层逻辑
|
||||||
respDTO, err := serviceExecutor(ctx, operatorID, primaryID, reqDTO)
|
respDTO, err := serviceExecutor(ctx, operatorID, primaryID, reqDTO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mapAndSendError(c, ctx, action, err, primaryID)
|
return mapAndSendError(reqContext, c, ctx, action, err, primaryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 发送成功响应
|
// 4. 发送成功响应
|
||||||
@@ -173,6 +178,7 @@ func handleAPIRequestWithResponse[Req any, Resp any](
|
|||||||
|
|
||||||
// handleNoBodyAPIRequestWithResponse 封装了处理不带请求体,但有路径参数和操作员ID,并返回响应DTO的API请求的通用逻辑。
|
// handleNoBodyAPIRequestWithResponse 封装了处理不带请求体,但有路径参数和操作员ID,并返回响应DTO的API请求的通用逻辑。
|
||||||
func handleNoBodyAPIRequestWithResponse[Resp any](
|
func handleNoBodyAPIRequestWithResponse[Resp any](
|
||||||
|
reqContext context.Context,
|
||||||
c *PigBatchController,
|
c *PigBatchController,
|
||||||
ctx echo.Context,
|
ctx echo.Context,
|
||||||
action string,
|
action string,
|
||||||
@@ -189,7 +195,7 @@ func handleNoBodyAPIRequestWithResponse[Resp any](
|
|||||||
// 2. 执行服务层逻辑
|
// 2. 执行服务层逻辑
|
||||||
respDTO, err := serviceExecutor(ctx, operatorID, primaryID)
|
respDTO, err := serviceExecutor(ctx, operatorID, primaryID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mapAndSendError(c, ctx, action, err, primaryID)
|
return mapAndSendError(reqContext, c, ctx, action, err, primaryID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 发送成功响应
|
// 3. 发送成功响应
|
||||||
@@ -198,6 +204,7 @@ func handleNoBodyAPIRequestWithResponse[Resp any](
|
|||||||
|
|
||||||
// handleQueryAPIRequestWithResponse 封装了处理带有查询参数并返回响应DTO的API请求的通用逻辑。
|
// handleQueryAPIRequestWithResponse 封装了处理带有查询参数并返回响应DTO的API请求的通用逻辑。
|
||||||
func handleQueryAPIRequestWithResponse[Query any, Resp any](
|
func handleQueryAPIRequestWithResponse[Query any, Resp any](
|
||||||
|
reqContext context.Context,
|
||||||
c *PigBatchController,
|
c *PigBatchController,
|
||||||
ctx echo.Context,
|
ctx echo.Context,
|
||||||
action string,
|
action string,
|
||||||
@@ -220,7 +227,7 @@ func handleQueryAPIRequestWithResponse[Query any, Resp any](
|
|||||||
respDTO, err := serviceExecutor(ctx, operatorID, queryDTO)
|
respDTO, err := serviceExecutor(ctx, operatorID, queryDTO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 对于列表查询,通常没有primaryID,所以传递0
|
// 对于列表查询,通常没有primaryID,所以传递0
|
||||||
return mapAndSendError(c, ctx, action, err, 0)
|
return mapAndSendError(reqContext, c, ctx, action, err, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 发送成功响应
|
// 4. 发送成功响应
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (c *PigBatchController) CreatePigBatch(ctx echo.Context) error {
|
|||||||
var req dto.PigBatchCreateDTO
|
var req dto.PigBatchCreateDTO
|
||||||
|
|
||||||
return handleAPIRequestWithResponse(
|
return handleAPIRequestWithResponse(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchCreateDTO) (*dto.PigBatchResponseDTO, error) {
|
||||||
// 对于创建操作,primaryID通常不从路径中获取,而是由服务层生成
|
// 对于创建操作,primaryID通常不从路径中获取,而是由服务层生成
|
||||||
return c.service.CreatePigBatch(reqCtx, operatorID, req)
|
return c.service.CreatePigBatch(reqCtx, operatorID, req)
|
||||||
@@ -67,7 +67,7 @@ func (c *PigBatchController) GetPigBatch(ctx echo.Context) error {
|
|||||||
const action = "获取猪批次"
|
const action = "获取猪批次"
|
||||||
|
|
||||||
return handleNoBodyAPIRequestWithResponse(
|
return handleNoBodyAPIRequestWithResponse(
|
||||||
c, ctx, action,
|
reqCtx, c, ctx, action,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint) (*dto.PigBatchResponseDTO, error) {
|
func(ctx echo.Context, operatorID uint, primaryID uint) (*dto.PigBatchResponseDTO, error) {
|
||||||
return c.service.GetPigBatch(reqCtx, primaryID)
|
return c.service.GetPigBatch(reqCtx, primaryID)
|
||||||
},
|
},
|
||||||
@@ -94,7 +94,7 @@ func (c *PigBatchController) UpdatePigBatch(ctx echo.Context) error {
|
|||||||
var req dto.PigBatchUpdateDTO
|
var req dto.PigBatchUpdateDTO
|
||||||
|
|
||||||
return handleAPIRequestWithResponse(
|
return handleAPIRequestWithResponse(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.PigBatchUpdateDTO) (*dto.PigBatchResponseDTO, error) {
|
||||||
return c.service.UpdatePigBatch(reqCtx, primaryID, req)
|
return c.service.UpdatePigBatch(reqCtx, primaryID, req)
|
||||||
},
|
},
|
||||||
@@ -118,7 +118,7 @@ func (c *PigBatchController) DeletePigBatch(ctx echo.Context) error {
|
|||||||
const action = "删除猪批次"
|
const action = "删除猪批次"
|
||||||
|
|
||||||
return handleNoBodyAPIRequest(
|
return handleNoBodyAPIRequest(
|
||||||
c, ctx, action,
|
reqCtx, c, ctx, action,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint) error {
|
||||||
return c.service.DeletePigBatch(reqCtx, primaryID)
|
return c.service.DeletePigBatch(reqCtx, primaryID)
|
||||||
},
|
},
|
||||||
@@ -143,7 +143,7 @@ func (c *PigBatchController) ListPigBatches(ctx echo.Context) error {
|
|||||||
var query dto.PigBatchQueryDTO
|
var query dto.PigBatchQueryDTO
|
||||||
|
|
||||||
return handleQueryAPIRequestWithResponse(
|
return handleQueryAPIRequestWithResponse(
|
||||||
c, ctx, action, &query,
|
reqCtx, c, ctx, action, &query,
|
||||||
func(ctx echo.Context, operatorID uint, query *dto.PigBatchQueryDTO) ([]*dto.PigBatchResponseDTO, error) {
|
func(ctx echo.Context, operatorID uint, query *dto.PigBatchQueryDTO) ([]*dto.PigBatchResponseDTO, error) {
|
||||||
return c.service.ListPigBatches(reqCtx, query.IsActive)
|
return c.service.ListPigBatches(reqCtx, query.IsActive)
|
||||||
},
|
},
|
||||||
@@ -169,7 +169,7 @@ func (c *PigBatchController) AssignEmptyPensToBatch(ctx echo.Context) error {
|
|||||||
var req dto.AssignEmptyPensToBatchRequest
|
var req dto.AssignEmptyPensToBatchRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.AssignEmptyPensToBatchRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.AssignEmptyPensToBatchRequest) error {
|
||||||
return c.service.AssignEmptyPensToBatch(reqCtx, primaryID, req.PenIDs, operatorID)
|
return c.service.AssignEmptyPensToBatch(reqCtx, primaryID, req.PenIDs, operatorID)
|
||||||
},
|
},
|
||||||
@@ -196,7 +196,7 @@ func (c *PigBatchController) ReclassifyPenToNewBatch(ctx echo.Context) error {
|
|||||||
var req dto.ReclassifyPenToNewBatchRequest
|
var req dto.ReclassifyPenToNewBatchRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.ReclassifyPenToNewBatchRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.ReclassifyPenToNewBatchRequest) error {
|
||||||
// primaryID 在这里是 fromBatchID
|
// primaryID 在这里是 fromBatchID
|
||||||
return c.service.ReclassifyPenToNewBatch(reqCtx, primaryID, req.ToBatchID, req.PenID, operatorID, req.Remarks)
|
return c.service.ReclassifyPenToNewBatch(reqCtx, primaryID, req.ToBatchID, req.PenID, operatorID, req.Remarks)
|
||||||
@@ -229,7 +229,7 @@ func (c *PigBatchController) RemoveEmptyPenFromBatch(ctx echo.Context) error {
|
|||||||
const action = "从猪批次移除空栏"
|
const action = "从猪批次移除空栏"
|
||||||
|
|
||||||
return handleNoBodyAPIRequest(
|
return handleNoBodyAPIRequest(
|
||||||
c, ctx, action,
|
reqCtx, c, ctx, action,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint) error {
|
||||||
// primaryID 在这里是 batchID
|
// primaryID 在这里是 batchID
|
||||||
penIDParam := ctx.Param("penID")
|
penIDParam := ctx.Param("penID")
|
||||||
@@ -269,7 +269,7 @@ func (c *PigBatchController) MovePigsIntoPen(ctx echo.Context) error {
|
|||||||
var req dto.MovePigsIntoPenRequest
|
var req dto.MovePigsIntoPenRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.MovePigsIntoPenRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.MovePigsIntoPenRequest) error {
|
||||||
return c.service.MovePigsIntoPen(reqCtx, primaryID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
return c.service.MovePigsIntoPen(reqCtx, primaryID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ func (c *PigBatchController) RecordSickPigs(ctx echo.Context) error {
|
|||||||
var req dto.RecordSickPigsRequest
|
var req dto.RecordSickPigsRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigsRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigsRequest) error {
|
||||||
return c.service.RecordSickPigs(reqCtx, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
return c.service.RecordSickPigs(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
"记录成功",
|
"记录成功",
|
||||||
nil, // 默认从 ":id" 路径参数提取ID
|
nil, // 默认从 ":id" 路径参数提取ID
|
||||||
@@ -52,7 +52,7 @@ func (c *PigBatchController) RecordSickPigRecovery(ctx echo.Context) error {
|
|||||||
var req dto.RecordSickPigRecoveryRequest
|
var req dto.RecordSickPigRecoveryRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigRecoveryRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigRecoveryRequest) error {
|
||||||
return c.service.RecordSickPigRecovery(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
return c.service.RecordSickPigRecovery(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
@@ -79,7 +79,7 @@ func (c *PigBatchController) RecordSickPigDeath(ctx echo.Context) error {
|
|||||||
var req dto.RecordSickPigDeathRequest
|
var req dto.RecordSickPigDeathRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigDeathRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigDeathRequest) error {
|
||||||
return c.service.RecordSickPigDeath(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
return c.service.RecordSickPigDeath(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
@@ -106,7 +106,7 @@ func (c *PigBatchController) RecordSickPigCull(ctx echo.Context) error {
|
|||||||
var req dto.RecordSickPigCullRequest
|
var req dto.RecordSickPigCullRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigCullRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordSickPigCullRequest) error {
|
||||||
return c.service.RecordSickPigCull(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
return c.service.RecordSickPigCull(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.TreatmentLocation, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
@@ -133,7 +133,7 @@ func (c *PigBatchController) RecordDeath(ctx echo.Context) error {
|
|||||||
var req dto.RecordDeathRequest
|
var req dto.RecordDeathRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordDeathRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordDeathRequest) error {
|
||||||
return c.service.RecordDeath(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks)
|
return c.service.RecordDeath(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
@@ -160,7 +160,7 @@ func (c *PigBatchController) RecordCull(ctx echo.Context) error {
|
|||||||
var req dto.RecordCullRequest
|
var req dto.RecordCullRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordCullRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.RecordCullRequest) error {
|
||||||
return c.service.RecordCull(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks)
|
return c.service.RecordCull(reqCtx, operatorID, primaryID, req.PenID, req.Quantity, req.HappenedAt, req.Remarks)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func (c *PigBatchController) SellPigs(ctx echo.Context) error {
|
|||||||
var req dto.SellPigsRequest
|
var req dto.SellPigsRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.SellPigsRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.SellPigsRequest) error {
|
||||||
return c.service.SellPigs(reqCtx, primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID)
|
return c.service.SellPigs(reqCtx, primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID)
|
||||||
},
|
},
|
||||||
@@ -50,7 +50,7 @@ func (c *PigBatchController) BuyPigs(ctx echo.Context) error {
|
|||||||
var req dto.BuyPigsRequest
|
var req dto.BuyPigsRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.BuyPigsRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.BuyPigsRequest) error {
|
||||||
return c.service.BuyPigs(reqCtx, primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID)
|
return c.service.BuyPigs(reqCtx, primaryID, req.PenID, req.Quantity, req.UnitPrice, req.TotalPrice, req.TraderName, req.TradeDate, req.Remarks, operatorID)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (c *PigBatchController) TransferPigsAcrossBatches(ctx echo.Context) error {
|
|||||||
var req dto.TransferPigsAcrossBatchesRequest
|
var req dto.TransferPigsAcrossBatchesRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsAcrossBatchesRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsAcrossBatchesRequest) error {
|
||||||
// primaryID 在这里是 sourceBatchID
|
// primaryID 在这里是 sourceBatchID
|
||||||
return c.service.TransferPigsAcrossBatches(reqCtx, primaryID, req.DestBatchID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
return c.service.TransferPigsAcrossBatches(reqCtx, primaryID, req.DestBatchID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
||||||
@@ -62,7 +62,7 @@ func (c *PigBatchController) TransferPigsWithinBatch(ctx echo.Context) error {
|
|||||||
var req dto.TransferPigsWithinBatchRequest
|
var req dto.TransferPigsWithinBatchRequest
|
||||||
|
|
||||||
return handleAPIRequest(
|
return handleAPIRequest(
|
||||||
c, ctx, action, &req,
|
reqCtx, c, ctx, action, &req,
|
||||||
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsWithinBatchRequest) error {
|
func(ctx echo.Context, operatorID uint, primaryID uint, req *dto.TransferPigsWithinBatchRequest) error {
|
||||||
// primaryID 在这里是 batchID
|
// primaryID 在这里是 batchID
|
||||||
return c.service.TransferPigsWithinBatch(reqCtx, primaryID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
return c.service.TransferPigsWithinBatch(reqCtx, primaryID, req.FromPenID, req.ToPenID, req.Quantity, operatorID, req.Remarks)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
|
"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/logs"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// AuditLogMiddleware 创建一个Echo中间件,用于在请求结束后记录用户操作审计日志。
|
// AuditLogMiddleware 创建一个Echo中间件,用于在请求结束后记录用户操作审计日志。
|
||||||
// 它依赖于控制器通过调用 SendSuccessWithAudit 或 SendErrorWithAudit 在上下文中设置的审计信息。
|
// 它依赖于控制器通过调用 SendSuccessWithAudit 或 SendErrorWithAudit 在上下文中设置的审计信息。
|
||||||
func AuditLogMiddleware(ctx context.Context, auditService audit.Service) echo.MiddlewareFunc {
|
func AuditLogMiddleware(ctx context.Context, auditService service.AuditService) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
newCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuditLogMiddleware")
|
newCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuditLogMiddleware")
|
||||||
@@ -35,8 +35,8 @@ func AuditLogMiddleware(ctx context.Context, auditService audit.Service) echo.Mi
|
|||||||
user, _ = userCtx.(*models.User)
|
user, _ = userCtx.(*models.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建 RequestContext
|
// 构建 AuditRequestContext
|
||||||
reqCtx := audit.RequestContext{
|
reqCtx := service.AuditRequestContext{
|
||||||
ClientIP: c.RealIP(),
|
ClientIP: c.RealIP(),
|
||||||
HTTPPath: c.Request().URL.Path,
|
HTTPPath: c.Request().URL.Path,
|
||||||
HTTPMethod: c.Request().Method,
|
HTTPMethod: c.Request().Method,
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/utils/token"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
// AuthMiddleware 创建一个Echo中间件,用于JWT身份验证
|
// AuthMiddleware 创建一个Echo中间件,用于JWT身份验证
|
||||||
// 它依赖于 TokenService 来解析和验证 token,并使用 UserRepository 来获取完整的用户信息
|
// 它依赖于 TokenService 来解析和验证 token,并使用 UserRepository 来获取完整的用户信息
|
||||||
func AuthMiddleware(ctx context.Context, tokenService token.Service, userRepo repository.UserRepository) echo.MiddlewareFunc {
|
func AuthMiddleware(ctx context.Context, tokenGenerator token.Generator, userRepo repository.UserRepository) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
reqCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuthMiddleware")
|
reqCtx := logs.AddFuncName(ctx, c.Request().Context(), "AuthMiddleware")
|
||||||
@@ -39,7 +39,7 @@ func AuthMiddleware(ctx context.Context, tokenService token.Service, userRepo re
|
|||||||
tokenString := parts[1]
|
tokenString := parts[1]
|
||||||
|
|
||||||
// 解析和验证 token
|
// 解析和验证 token
|
||||||
claims, err := tokenService.ParseToken(tokenString)
|
claims, err := tokenGenerator.ParseToken(tokenString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "无效的Token")
|
return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "无效的Token")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestContext 封装了审计日志所需的请求上下文信息
|
// AuditRequestContext 封装了审计日志所需的请求上下文信息
|
||||||
type RequestContext struct {
|
type AuditRequestContext struct {
|
||||||
ClientIP string
|
ClientIP string
|
||||||
HTTPPath string
|
HTTPPath string
|
||||||
HTTPMethod string
|
HTTPMethod string
|
||||||
@@ -19,7 +19,7 @@ type RequestContext struct {
|
|||||||
|
|
||||||
// AuditService 定义了审计服务的接口
|
// AuditService 定义了审计服务的接口
|
||||||
type AuditService interface {
|
type AuditService interface {
|
||||||
LogAction(ctx context.Context, user *models.User, reqCtx RequestContext, actionType, description string, targetResource interface{}, status models.AuditStatus, resultDetails string)
|
LogAction(ctx context.Context, user *models.User, reqCtx AuditRequestContext, actionType, description string, targetResource interface{}, status models.AuditStatus, resultDetails string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// auditService 是 AuditService 接口的实现
|
// auditService 是 AuditService 接口的实现
|
||||||
@@ -37,7 +37,7 @@ func NewAuditService(ctx context.Context, repo repository.UserActionLogRepositor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LogAction 记录一个用户操作。它在一个新的 goroutine 中异步执行,以避免阻塞主请求。
|
// LogAction 记录一个用户操作。它在一个新的 goroutine 中异步执行,以避免阻塞主请求。
|
||||||
func (s *auditService) LogAction(ctx context.Context, user *models.User, reqCtx RequestContext, actionType, description string, targetResource interface{}, status models.AuditStatus, resultDetails string) {
|
func (s *auditService) LogAction(ctx context.Context, user *models.User, reqCtx AuditRequestContext, actionType, description string, targetResource interface{}, status models.AuditStatus, resultDetails string) {
|
||||||
serviceCtx, logger := logs.Trace(ctx, s.ctx, "LogAction")
|
serviceCtx, logger := logs.Trace(ctx, s.ctx, "LogAction")
|
||||||
|
|
||||||
// 不再从 context 中获取用户信息,直接使用传入的 user 对象
|
// 不再从 context 中获取用户信息,直接使用传入的 user 对象
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ func (s *pigFarmService) DeletePen(ctx context.Context, id uint) error {
|
|||||||
func (s *pigFarmService) UpdatePenStatus(ctx context.Context, id uint, newStatus models.PenStatus) (*dto.PenResponse, error) {
|
func (s *pigFarmService) UpdatePenStatus(ctx context.Context, id uint, newStatus models.PenStatus) (*dto.PenResponse, error) {
|
||||||
serviceCtx, logger := logs.Trace(ctx, s.ctx, "UpdatePenStatus")
|
serviceCtx, logger := logs.Trace(ctx, s.ctx, "UpdatePenStatus")
|
||||||
var updatedPen *models.Pen
|
var updatedPen *models.Pen
|
||||||
err := s.uow.ExecuteInTransaction(func(tx *gorm.DB) error {
|
err := s.uow.ExecuteInTransaction(serviceCtx, func(tx *gorm.DB) error {
|
||||||
pen, err := s.penRepository.GetPenByIDTx(serviceCtx, tx, id)
|
pen, err := s.penRepository.GetPenByIDTx(serviceCtx, tx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func (s *userService) Login(ctx context.Context, req *dto.LoginRequest) (*dto.Lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 登录成功,生成 JWT token
|
// 登录成功,生成 JWT token
|
||||||
tokenString, err := s.tokenService.GenerateToken(user.ID)
|
tokenString, err := s.tokenGenerator.GenerateToken(user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("登录: 生成令牌失败: %v", err)
|
logger.Errorf("登录: 生成令牌失败: %v", err)
|
||||||
return nil, errors.New("登录失败,无法生成认证信息")
|
return nil, errors.New("登录失败,无法生成认证信息")
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (app *Application) Start() error {
|
|||||||
logger.Info("应用启动中...")
|
logger.Info("应用启动中...")
|
||||||
|
|
||||||
// 1. 启动底层监听器
|
// 1. 启动底层监听器
|
||||||
if err := app.Infra.lora.loraListener.Listen(); err != nil {
|
if err := app.Infra.lora.loraListener.Listen(startCtx); err != nil {
|
||||||
return fmt.Errorf("启动 LoRa Mesh 监听器失败: %w", err)
|
return fmt.Errorf("启动 LoRa Mesh 监听器失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,12 +117,12 @@ func (app *Application) Stop() error {
|
|||||||
app.Domain.planService.Stop(stopCtx)
|
app.Domain.planService.Stop(stopCtx)
|
||||||
|
|
||||||
// 断开数据库连接
|
// 断开数据库连接
|
||||||
if err := app.Infra.storage.Disconnect(); err != nil {
|
if err := app.Infra.storage.Disconnect(stopCtx); err != nil {
|
||||||
logger.Errorw("数据库连接断开失败", "error", err)
|
logger.Errorw("数据库连接断开失败", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭 LoRa Mesh 监听器
|
// 关闭 LoRa Mesh 监听器
|
||||||
if err := app.Infra.lora.loraListener.Stop(); err != nil {
|
if err := app.Infra.lora.loraListener.Stop(stopCtx); err != nil {
|
||||||
logger.Errorw("LoRa Mesh 监听器关闭失败", "error", err)
|
logger.Errorw("LoRa Mesh 监听器关闭失败", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// traceKey 是日志中用于调用链的字段名,必须与 GetLogger 中使用的保持一致。
|
// traceKey 是日志中用于调用链的字段名,必须与 GetLogger 中使用的保持一致。
|
||||||
const traceKey = "逻辑调用链"
|
const traceKey = "Trace"
|
||||||
|
|
||||||
// coloredConsoleEncoder 是一个自定义的 zapcore.Encoder,它实现了两个核心功能:
|
// coloredConsoleEncoder 是一个自定义的 zapcore.Encoder,它实现了两个核心功能:
|
||||||
// 1. 为控制台输出的日志行根据级别添加 ANSI 颜色。
|
// 1. 为控制台输出的日志行根据级别添加 ANSI 颜色。
|
||||||
|
|||||||
Reference in New Issue
Block a user