2025-10-31 15:38:10 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-05 19:57:30 +08:00
|
|
|
|
"context"
|
2025-10-31 15:38:10 +08:00
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"errors"
|
2025-11-03 16:46:23 +08:00
|
|
|
|
"fmt"
|
2025-10-31 15:38:10 +08:00
|
|
|
|
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/dto"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
2025-11-05 19:57:30 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
2025-10-31 15:38:10 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
var (
|
|
|
|
|
|
// ErrDeviceInUse 表示设备正在被任务使用,无法删除
|
|
|
|
|
|
ErrDeviceInUse = errors.New("设备正在被一个或多个任务使用,无法删除")
|
|
|
|
|
|
|
|
|
|
|
|
// ErrAreaControllerInUse 表示区域主控正在被设备使用,无法删除
|
|
|
|
|
|
ErrAreaControllerInUse = errors.New("区域主控正在被一个或多个设备使用,无法删除")
|
|
|
|
|
|
|
|
|
|
|
|
// ErrDeviceTemplateInUse 表示设备模板正在被设备使用,无法删除
|
|
|
|
|
|
ErrDeviceTemplateInUse = errors.New("设备模板正在被一个或多个设备使用,无法删除")
|
|
|
|
|
|
)
|
2025-11-03 16:46:23 +08:00
|
|
|
|
|
2025-11-03 17:27:29 +08:00
|
|
|
|
// DeviceService 定义了应用层的设备服务接口,用于协调设备相关的业务逻辑。
|
2025-10-31 15:38:10 +08:00
|
|
|
|
// DeviceService 定义了应用层的设备服务接口,用于协调设备相关的业务逻辑。
|
|
|
|
|
|
type DeviceService interface {
|
2025-11-05 19:57:30 +08:00
|
|
|
|
CreateDevice(ctx context.Context, req *dto.CreateDeviceRequest) (*dto.DeviceResponse, error)
|
|
|
|
|
|
GetDevice(ctx context.Context, id uint) (*dto.DeviceResponse, error)
|
|
|
|
|
|
ListDevices(ctx context.Context) ([]*dto.DeviceResponse, error)
|
|
|
|
|
|
UpdateDevice(ctx context.Context, id uint, req *dto.UpdateDeviceRequest) (*dto.DeviceResponse, error)
|
|
|
|
|
|
DeleteDevice(ctx context.Context, id uint) error
|
|
|
|
|
|
ManualControl(ctx context.Context, id uint, req *dto.ManualControlDeviceRequest) error
|
|
|
|
|
|
|
|
|
|
|
|
CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error)
|
|
|
|
|
|
GetAreaController(ctx context.Context, id uint) (*dto.AreaControllerResponse, error)
|
|
|
|
|
|
ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error)
|
|
|
|
|
|
UpdateAreaController(ctx context.Context, id uint, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error)
|
|
|
|
|
|
DeleteAreaController(ctx context.Context, id uint) error
|
|
|
|
|
|
|
|
|
|
|
|
CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
|
|
|
|
|
|
GetDeviceTemplate(ctx context.Context, id uint) (*dto.DeviceTemplateResponse, error)
|
|
|
|
|
|
ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error)
|
|
|
|
|
|
UpdateDeviceTemplate(ctx context.Context, id uint, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error)
|
|
|
|
|
|
DeleteDeviceTemplate(ctx context.Context, id uint) error
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// deviceService 是 DeviceService 接口的具体实现。
|
|
|
|
|
|
type deviceService struct {
|
2025-11-10 20:37:07 +08:00
|
|
|
|
ctx context.Context
|
|
|
|
|
|
deviceRepo repository.DeviceRepository
|
|
|
|
|
|
areaControllerRepo repository.AreaControllerRepository
|
|
|
|
|
|
deviceTemplateRepo repository.DeviceTemplateRepository
|
|
|
|
|
|
deviceDomainSvc device.Service
|
|
|
|
|
|
thresholdAlarmService ThresholdAlarmService
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewDeviceService 创建一个新的 DeviceService 实例。
|
|
|
|
|
|
func NewDeviceService(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
ctx context.Context,
|
2025-10-31 15:38:10 +08:00
|
|
|
|
deviceRepo repository.DeviceRepository,
|
|
|
|
|
|
areaControllerRepo repository.AreaControllerRepository,
|
|
|
|
|
|
deviceTemplateRepo repository.DeviceTemplateRepository,
|
|
|
|
|
|
deviceDomainSvc device.Service,
|
2025-11-10 20:37:07 +08:00
|
|
|
|
thresholdAlarmService ThresholdAlarmService,
|
2025-10-31 15:38:10 +08:00
|
|
|
|
) DeviceService {
|
|
|
|
|
|
return &deviceService{
|
2025-11-10 20:37:07 +08:00
|
|
|
|
ctx: ctx,
|
|
|
|
|
|
deviceRepo: deviceRepo,
|
|
|
|
|
|
areaControllerRepo: areaControllerRepo,
|
|
|
|
|
|
deviceTemplateRepo: deviceTemplateRepo,
|
|
|
|
|
|
deviceDomainSvc: deviceDomainSvc,
|
|
|
|
|
|
thresholdAlarmService: thresholdAlarmService,
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Devices ---
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) CreateDevice(ctx context.Context, req *dto.CreateDeviceRequest) (*dto.DeviceResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateDevice")
|
2025-10-31 15:38:10 +08:00
|
|
|
|
propertiesJSON, err := json.Marshal(req.Properties)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err // Consider wrapping this error for better context
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
device := &models.Device{
|
|
|
|
|
|
Name: req.Name,
|
|
|
|
|
|
DeviceTemplateID: req.DeviceTemplateID,
|
|
|
|
|
|
AreaControllerID: req.AreaControllerID,
|
|
|
|
|
|
Location: req.Location,
|
|
|
|
|
|
Properties: propertiesJSON,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := device.SelfCheck(); err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.deviceRepo.Create(serviceCtx, device); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
createdDevice, err := s.deviceRepo.FindByID(serviceCtx, device.ID)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewDeviceResponse(createdDevice)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) GetDevice(ctx context.Context, id uint) (*dto.DeviceResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetDevice")
|
|
|
|
|
|
device, err := s.deviceRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewDeviceResponse(device)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) ListDevices(ctx context.Context) ([]*dto.DeviceResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListDevices")
|
|
|
|
|
|
devices, err := s.deviceRepo.ListAll(serviceCtx)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewListDeviceResponse(devices)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) UpdateDevice(ctx context.Context, id uint, req *dto.UpdateDeviceRequest) (*dto.DeviceResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateDevice")
|
|
|
|
|
|
existingDevice, err := s.deviceRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
propertiesJSON, err := json.Marshal(req.Properties)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
existingDevice.Name = req.Name
|
|
|
|
|
|
existingDevice.DeviceTemplateID = req.DeviceTemplateID
|
|
|
|
|
|
existingDevice.AreaControllerID = req.AreaControllerID
|
|
|
|
|
|
existingDevice.Location = req.Location
|
|
|
|
|
|
existingDevice.Properties = propertiesJSON
|
|
|
|
|
|
|
|
|
|
|
|
if err := existingDevice.SelfCheck(); err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.deviceRepo.Update(serviceCtx, existingDevice); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
updatedDevice, err := s.deviceRepo.FindByID(serviceCtx, existingDevice.ID)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewDeviceResponse(updatedDevice)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) DeleteDevice(ctx context.Context, id uint) error {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteDevice")
|
2025-10-31 15:38:10 +08:00
|
|
|
|
|
2025-11-03 16:46:23 +08:00
|
|
|
|
// 检查设备是否存在
|
2025-11-05 19:57:30 +08:00
|
|
|
|
_, err := s.deviceRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
2025-11-03 16:46:23 +08:00
|
|
|
|
return err // 如果未找到,会返回 gorm.ErrRecordNotFound
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在删除前检查设备是否被任务使用
|
2025-11-10 21:14:36 +08:00
|
|
|
|
inUse, err := s.deviceRepo.IsDeviceInUse(serviceCtx, id, []models.TaskType{models.TaskTypeDeviceThresholdCheck})
|
2025-11-03 16:46:23 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 如果检查过程中发生数据库错误,则返回错误
|
|
|
|
|
|
return fmt.Errorf("检查设备使用情况失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if inUse {
|
|
|
|
|
|
// 如果设备正在被使用,则返回特定的业务错误
|
|
|
|
|
|
return ErrDeviceInUse
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-10 21:14:36 +08:00
|
|
|
|
// TODO 这个应该用事务处理
|
|
|
|
|
|
err = s.thresholdAlarmService.DeleteDeviceThresholdAlarmByDeviceID(serviceCtx, id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("删除设备阈值告警失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 16:46:23 +08:00
|
|
|
|
// 只有在未被使用时,才执行删除操作
|
2025-11-05 19:57:30 +08:00
|
|
|
|
return s.deviceRepo.Delete(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) ManualControl(ctx context.Context, id uint, req *dto.ManualControlDeviceRequest) error {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ManualControl")
|
|
|
|
|
|
dev, err := s.deviceRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if req.Action == nil {
|
2025-11-05 19:57:30 +08:00
|
|
|
|
return s.deviceDomainSvc.Collect(serviceCtx, dev.AreaControllerID, []*models.Device{dev})
|
2025-10-31 15:38:10 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
action := device.DeviceActionStart
|
|
|
|
|
|
switch *req.Action {
|
|
|
|
|
|
case "off":
|
|
|
|
|
|
action = device.DeviceActionStop
|
|
|
|
|
|
case "on":
|
|
|
|
|
|
action = device.DeviceActionStart
|
|
|
|
|
|
default:
|
|
|
|
|
|
return errors.New("invalid action")
|
|
|
|
|
|
}
|
2025-11-05 19:57:30 +08:00
|
|
|
|
return s.deviceDomainSvc.Switch(serviceCtx, dev, action)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Area Controllers ---
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) CreateAreaController(ctx context.Context, req *dto.CreateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateAreaController")
|
2025-10-31 15:38:10 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.areaControllerRepo.Create(serviceCtx, ac); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewAreaControllerResponse(ac)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) GetAreaController(ctx context.Context, id uint) (*dto.AreaControllerResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetAreaController")
|
|
|
|
|
|
ac, err := s.areaControllerRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewAreaControllerResponse(ac)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) ListAreaControllers(ctx context.Context) ([]*dto.AreaControllerResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListAreaControllers")
|
|
|
|
|
|
acs, err := s.areaControllerRepo.ListAll(serviceCtx)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewListAreaControllerResponse(acs)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) UpdateAreaController(ctx context.Context, id uint, req *dto.UpdateAreaControllerRequest) (*dto.AreaControllerResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateAreaController")
|
|
|
|
|
|
existingAC, err := s.areaControllerRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.areaControllerRepo.Update(serviceCtx, existingAC); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewAreaControllerResponse(existingAC)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) DeleteAreaController(ctx context.Context, id uint) error {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteAreaController")
|
2025-10-31 15:38:10 +08:00
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
// 1. 检查是否存在
|
2025-11-05 19:57:30 +08:00
|
|
|
|
_, err := s.areaControllerRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
2025-11-03 17:11:51 +08:00
|
|
|
|
return err // 如果未找到,gorm会返回 ErrRecordNotFound
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
// 2. 检查是否被使用(业务逻辑)
|
2025-11-10 21:14:36 +08:00
|
|
|
|
inUse, err := s.areaControllerRepo.IsAreaControllerUsedByTasks(serviceCtx, id, []models.TaskType{models.TaskTypeAreaCollectorThresholdCheck})
|
2025-11-03 17:11:51 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err // 返回数据库检查错误
|
|
|
|
|
|
}
|
|
|
|
|
|
if inUse {
|
|
|
|
|
|
return ErrAreaControllerInUse // 返回业务错误
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-10 21:14:36 +08:00
|
|
|
|
// TODO 这个应该用事务处理
|
|
|
|
|
|
err = s.thresholdAlarmService.DeleteAreaThresholdAlarmByAreaControllerID(serviceCtx, id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("删除区域阈值告警失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
// 3. 执行删除
|
2025-11-05 19:57:30 +08:00
|
|
|
|
return s.areaControllerRepo.Delete(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Device Templates ---
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) CreateDeviceTemplate(ctx context.Context, req *dto.CreateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "CreateDeviceTemplate")
|
2025-10-31 15:38:10 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.deviceTemplateRepo.Create(serviceCtx, deviceTemplate); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewDeviceTemplateResponse(deviceTemplate)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) GetDeviceTemplate(ctx context.Context, id uint) (*dto.DeviceTemplateResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "GetDeviceTemplate")
|
|
|
|
|
|
deviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewDeviceTemplateResponse(deviceTemplate)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) ListDeviceTemplates(ctx context.Context) ([]*dto.DeviceTemplateResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "ListDeviceTemplates")
|
|
|
|
|
|
deviceTemplates, err := s.deviceTemplateRepo.ListAll(serviceCtx)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return dto.NewListDeviceTemplateResponse(deviceTemplates)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) UpdateDeviceTemplate(ctx context.Context, id uint, req *dto.UpdateDeviceTemplateRequest) (*dto.DeviceTemplateResponse, error) {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "UpdateDeviceTemplate")
|
|
|
|
|
|
existingDeviceTemplate, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := s.deviceTemplateRepo.Update(serviceCtx, existingDeviceTemplate); err != nil {
|
2025-10-31 15:38:10 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dto.NewDeviceTemplateResponse(existingDeviceTemplate)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 19:57:30 +08:00
|
|
|
|
func (s *deviceService) DeleteDeviceTemplate(ctx context.Context, id uint) error {
|
|
|
|
|
|
serviceCtx := logs.AddFuncName(ctx, s.ctx, "DeleteDeviceTemplate")
|
2025-11-03 17:11:51 +08:00
|
|
|
|
|
|
|
|
|
|
// 1. 检查是否存在
|
2025-11-05 19:57:30 +08:00
|
|
|
|
_, err := s.deviceTemplateRepo.FindByID(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
// 2. 检查是否被使用(业务逻辑)
|
2025-11-05 19:57:30 +08:00
|
|
|
|
inUse, err := s.deviceTemplateRepo.IsInUse(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2025-11-03 17:11:51 +08:00
|
|
|
|
if inUse {
|
|
|
|
|
|
return ErrDeviceTemplateInUse // 返回业务错误
|
|
|
|
|
|
}
|
2025-10-31 15:38:10 +08:00
|
|
|
|
|
2025-11-03 17:11:51 +08:00
|
|
|
|
// 3. 执行删除
|
2025-11-05 19:57:30 +08:00
|
|
|
|
return s.deviceTemplateRepo.Delete(serviceCtx, id)
|
2025-10-31 15:38:10 +08:00
|
|
|
|
}
|