Files
junhong_cmp_fiber/internal/service/device/binding.go
huang 3b54850f1b feat(03.1-01): 修复静态 DTO 映射缺口
- toDeviceResponse() 补全 5 个 DB 缓存字段(OnlineStatus/LastOnlineTime/SoftwareVersion/SwitchMode/LastGatewaySyncAt)
- ListBindings() 补全 IsCurrent 字段映射
- buildDeviceResolveResponse() 补全 isCurrentMap + BoundCardInfo.IsCurrent + 5 个 DB 缓存字段
- GetRealtimeStatus() device case 补全 isCurrentMap + BoundCardInfo.IsCurrent
2026-03-28 13:19:09 +08:00

149 lines
3.9 KiB
Go

package device
import (
"context"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"gorm.io/gorm"
)
func (s *Service) ListBindings(ctx context.Context, deviceID uint) (*dto.ListDeviceCardsResponse, error) {
device, err := s.deviceStore.GetByID(ctx, deviceID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "设备不存在")
}
return nil, err
}
bindings, err := s.deviceSimBindingStore.ListByDeviceID(ctx, device.ID)
if err != nil {
return nil, err
}
cardIDs := make([]uint, 0, len(bindings))
for _, binding := range bindings {
cardIDs = append(cardIDs, binding.IotCardID)
}
var cards []*model.IotCard
if len(cardIDs) > 0 {
cards, err = s.iotCardStore.GetByIDs(ctx, cardIDs)
if err != nil {
return nil, err
}
}
cardMap := make(map[uint]*model.IotCard)
for _, card := range cards {
cardMap[card.ID] = card
}
responses := make([]*dto.DeviceCardBindingResponse, 0, len(bindings))
for _, binding := range bindings {
card := cardMap[binding.IotCardID]
if card == nil {
continue
}
resp := &dto.DeviceCardBindingResponse{
ID: binding.ID,
SlotPosition: binding.SlotPosition,
IotCardID: binding.IotCardID,
ICCID: card.ICCID,
MSISDN: card.MSISDN,
CarrierName: card.CarrierName, // 直接使用 IotCard 的冗余字段
Status: card.Status,
BindTime: binding.BindTime,
IsCurrent: binding.IsCurrent,
}
responses = append(responses, resp)
}
return &dto.ListDeviceCardsResponse{
Bindings: responses,
}, nil
}
func (s *Service) BindCard(ctx context.Context, deviceID uint, req *dto.BindCardToDeviceRequest) (*dto.BindCardToDeviceResponse, error) {
device, err := s.deviceStore.GetByID(ctx, deviceID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "设备不存在")
}
return nil, err
}
if req.SlotPosition > device.MaxSimSlots {
return nil, errors.New(errors.CodeInvalidParam, "插槽位置超出设备最大插槽数")
}
existingBinding, err := s.deviceSimBindingStore.GetByDeviceAndSlot(ctx, device.ID, req.SlotPosition)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
if existingBinding != nil {
return nil, errors.New(errors.CodeConflict, "该插槽已有绑定的卡")
}
card, err := s.iotCardStore.GetByID(ctx, req.IotCardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeIotCardNotFound)
}
return nil, err
}
activeBinding, err := s.deviceSimBindingStore.GetActiveBindingByCardID(ctx, card.ID)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
if activeBinding != nil {
return nil, errors.New(errors.CodeIotCardBoundToDevice, "该卡已绑定到其他设备")
}
binding := &model.DeviceSimBinding{
DeviceID: device.ID,
IotCardID: card.ID,
SlotPosition: req.SlotPosition,
BindStatus: 1,
}
if err := s.deviceSimBindingStore.Create(ctx, binding); err != nil {
return nil, err
}
return &dto.BindCardToDeviceResponse{
BindingID: binding.ID,
Message: "绑定成功",
}, nil
}
func (s *Service) UnbindCard(ctx context.Context, deviceID uint, cardID uint) (*dto.UnbindCardFromDeviceResponse, error) {
device, err := s.deviceStore.GetByID(ctx, deviceID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "设备不存在")
}
return nil, err
}
binding, err := s.deviceSimBindingStore.GetByDeviceAndCard(ctx, device.ID, cardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "该卡未绑定到此设备")
}
return nil, err
}
if err := s.deviceSimBindingStore.Unbind(ctx, binding.ID); err != nil {
return nil, err
}
return &dto.UnbindCardFromDeviceResponse{
Message: "解绑成功",
}, nil
}