ListSensorData

This commit is contained in:
2025-10-18 15:31:05 +08:00
parent 3b967aa449
commit 05820438d0
4 changed files with 232 additions and 1 deletions

View File

@@ -0,0 +1,81 @@
package monitor
import (
"errors"
"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"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/gin-gonic/gin"
)
// Controller 监控控制器,封装了所有与数据监控相关的业务逻辑
type Controller struct {
monitorService *service.MonitorService
logger *logs.Logger
}
// NewController 创建一个新的监控控制器实例
func NewController(monitorService *service.MonitorService, logger *logs.Logger) *Controller {
return &Controller{
monitorService: monitorService,
logger: logger,
}
}
// ListSensorData godoc
// @Summary 获取传感器数据列表
// @Description 根据提供的过滤条件,分页获取传感器数据
// @Tags 数据监控
// @Security BearerAuth
// @Produce json
// @Param query query dto.ListSensorDataRequest true "查询参数"
// @Success 200 {object} controller.Response{data=dto.ListSensorDataResponse}
// @Router /api/v1/monitor/sensor-data [get]
func (c *Controller) ListSensorData(ctx *gin.Context) {
const actionType = "获取传感器数据列表"
// --- 绑定并校验查询参数 ---
var req dto.ListSensorDataRequest
if err := ctx.ShouldBindQuery(&req); err != nil {
c.logger.Errorf("%s: 参数绑定失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的查询参数: "+err.Error(), actionType, "参数绑定失败", req)
return
}
// --- 将请求 DTO 转换为仓库层需要的 Options 结构体 ---
opts := repository.SensorDataListOptions{
DeviceID: req.DeviceID,
OrderBy: req.OrderBy,
StartTime: req.StartTime,
EndTime: req.EndTime,
}
if req.SensorType != nil {
sensorType := models.SensorType(*req.SensorType)
opts.SensorType = &sensorType
}
// --- 调用服务层 ---
data, total, err := c.monitorService.ListSensorData(opts, req.Page, req.PageSize)
if err != nil {
// --- 错误处理:区分参数错误和内部错误 ---
if errors.Is(err, repository.ErrInvalidPagination) {
c.logger.Warnf("%s: 无效的分页参数: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeBadRequest, "无效的分页参数: "+err.Error(), actionType, "无效分页参数", req)
return
}
// 其他未知错误按内部错误处理
c.logger.Errorf("%s: 服务层查询失败: %v", actionType, err)
controller.SendErrorWithAudit(ctx, controller.CodeInternalError, "获取传感器数据失败: "+err.Error(), actionType, "服务层查询失败", req)
return
}
// --- 构建并发送成功响应 ---
resp := dto.NewListSensorDataResponse(data, total, req.Page, req.PageSize)
c.logger.Infof("%s: 成功, 获取到 %d 条记录, 总计 %d 条", actionType, len(data), total)
controller.SendSuccessWithAudit(ctx, controller.CodeSuccess, "获取传感器数据成功", resp, actionType, "获取传感器数据成功", req)
}

View File

@@ -0,0 +1,65 @@
package dto
import (
"encoding/json"
"time"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
)
// ListSensorDataRequest 定义了获取传感器数据列表的请求参数
// 使用 form 标签以便 Gin 可以从查询字符串中绑定数据
type ListSensorDataRequest struct {
Page int `form:"page,default=1"`
PageSize int `form:"pageSize,default=10"`
DeviceID *uint `form:"device_id"`
SensorType *string `form:"sensor_type"`
StartTime *time.Time `form:"start_time" time_format:"rfc3339"`
EndTime *time.Time `form:"end_time" time_format:"rfc3339"`
OrderBy string `form:"order_by"`
}
// SensorDataDTO 是用于API响应的传感器数据结构
type SensorDataDTO struct {
Time time.Time `json:"time"`
DeviceID uint `json:"device_id"`
RegionalControllerID uint `json:"regional_controller_id"`
SensorType models.SensorType `json:"sensor_type"`
Data json.RawMessage `json:"data"` // 使用 json.RawMessage 以便直接输出 JSON 内容
}
// PaginationDTO 定义了分页信息的标准结构
type PaginationDTO struct {
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
// ListSensorDataResponse 是获取传感器数据列表的响应结构
type ListSensorDataResponse struct {
List []SensorDataDTO `json:"list"`
Pagination PaginationDTO `json:"pagination"`
}
// NewListSensorDataResponse 从模型数据创建列表响应 DTO
func NewListSensorDataResponse(data []models.SensorData, total int64, page, pageSize int) *ListSensorDataResponse {
dtos := make([]SensorDataDTO, len(data))
for i, item := range data {
dtos[i] = SensorDataDTO{
Time: item.Time,
DeviceID: item.DeviceID,
RegionalControllerID: item.RegionalControllerID,
SensorType: item.SensorType,
Data: json.RawMessage(item.Data), // gorm.datatypes.JSON 是 []byte, 可直接转换为 json.RawMessage
}
}
return &ListSensorDataResponse{
List: dtos,
Pagination: PaginationDTO{
Total: total,
Page: page,
PageSize: pageSize,
},
}
}

View File

@@ -0,0 +1,26 @@
package service
import (
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
)
// MonitorService 定义了监控相关的业务逻辑服务
type MonitorService struct {
sensorDataRepo repository.SensorDataRepository
// 在这里可以添加其他超表模型的仓库依赖
}
// NewMonitorService 创建一个新的 MonitorService 实例
func NewMonitorService(sensorDataRepo repository.SensorDataRepository) *MonitorService {
return &MonitorService{
sensorDataRepo: sensorDataRepo,
}
}
// ListSensorData 负责处理查询传感器数据列表的业务逻辑
func (s *MonitorService) ListSensorData(opts repository.SensorDataListOptions, page, pageSize int) ([]models.SensorData, int64, error) {
// 目前业务逻辑只是简单地将请求透传给仓库层。
// 未来任何与查询传感器数据相关的业务规则(如权限校验、数据聚合等)都应在此处实现。
return s.sensorDataRepo.List(opts, page, pageSize)
}